home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1993…stman Always Clicks Twice / ADC Developer CD (1993-01) (''The Postman Always Clicks Twice'')_iso / Dev.CD 199301.iso / Technical Documentation / Mac Tech Notes (DocViewer) / TN-Graphics / TN-Graphics
Encoding:
Text File  |  1992-11-18  |  1.6 MB  |  5,929 lines  |  [ONLN/HLX2]

Text Truncated. Only the first 1MB is shown below. Download the file for the complete contents.
  1. 32-Bit QuickDraw:  Version 1.2 Features
  2. Imaging    M.IM.32BitQD
  3. Written by:    Guillermo Ortiz    April 1990
  4. This Technical Note describes the changes and enhancements to 32-Bit QuickDraw from version 1.0 (as shipped on the original Color Disk) to version 1.2, which ships with System Software 6.0.5 and later.  This Note assumes familiarity with Inside Macintosh, Volume V, Color QuickDraw, and 32-Bit QuickDraw release notes.
  5. 32-Bit QuickDraw
  6. Version 1.0 of 32-Bit QuickDraw shipped in May 1989 in response to the growing need for Color QuickDraw support for direct color devices and pictures (PICT2) and video boards for large-screen monitors which require 32-bit addressing for black and white operation.  This original version of 32-Bit QuickDraw was a separate file that had to be copied manually into the System Folder.  With the introduction of the Macintosh IIci, Apple put 32-Bit QuickDraw into ROM.  Now System Software 6.0.5 and later offer 32-Bit QuickDraw as an integral part of the System Software which can be installed by the standard Installer (although the file is still separate).
  7. This Note describes the changes and enhancements in version 1.2 of 32-Bit QuickDraw from version 1.0.  Beginning with version 1.2, QuickDraw functionality is identical on all Color QuickDraw machines, including all the performance improvements which were originally only available in the IIci ROM.
  8. New Features (In No Particular Order)
  9. PICTs Contain Font Name Information
  10. Every time you draw text inside of an _OpenPicture and _ClosePicture pair, QuickDraw stores the name of the current font and uses it when playing back the picture.  The opcode used to save this information is $002C and its data is as follows:
  11.     PictFontInfo = Record
  12.                      length   : Integer;    { length of data in bytes }
  13.                      fontID   : Integer;    { ID in the source system }
  14.                      fontName : Str255;
  15.                    END;
  16. QuickDraw only saves this information one time for each font used in a picture.  When QuickDraw plays back a picture, it uses the fontID as a reference into the list of font names which are used to set the correct font on the target system.
  17. For example, the following code:
  18.     GetFNum('Venice', theFontID);    { Set a font before opening PICT}
  19.     TextFont(theFontID);
  20.     pHand2 := OpenPicture (pictRect);
  21.         MoveTo(20,20);
  22.         DrawString(' Better be Venice');
  23.         GetFNum('Geneva', theFontID);
  24.         TextFont(theFontID);
  25.         MoveTo(20,40);
  26.         DrawString('Geneva');
  27.         GetFNum('New York', theFontID);
  28.         TextFont(theFontID);
  29.         MoveTo(20,60);
  30.         DrawString('New York');
  31.         GetFNum('Geneva', theFontID);
  32.         TextFont(theFontID);
  33.         MoveTo(20,80);
  34.         DrawString('Geneva');
  35.     ClosePicture; 
  36. generates a picture containing font information like this:
  37.     OpCode 0x002C {9, 
  38.         "0005 0656 656E 6963 65"}              /* save current font     */
  39.     TxFont 'venice'
  40.     DHDVText {20, 20, " Better be Venice"}
  41.     OpCode 0x002C {9,                          /* save next font name   */
  42.         "0003 0647 656E 6576 61"}
  43.     TxFont 'geneva'
  44.     DVText {20, "Geneva"}
  45.     OpCode 0x002C {11,                         /* ditto                 */
  46.         "0002 084E 6577 2059 6F72 6B"}
  47.     TxFont 'newYork'
  48.     DVText {20, "New York"}
  49.     TxFont 'geneva'                            /* second Geneva does not
  50.                                                  need another $002C guy */
  51.     DVText {20, "Geneva"}
  52. This feature works regardless of the type of picture being saved, including old style PICTs in a black and white port.  Using _OpenCPicture instead of _OpenPicture to start a recording session results in the same functionality.
  53. Direct PixPat Structures Now Supported
  54. QuickDraw now supports 16-bit and 32-bit per pixel PixPat structures (patType = 1).  In addition, it now supports a new patType (3) which uses dithering whenever 16-bit or 32-bit  pixel patterns are displayed on indexed devices.
  55. Direct 'cicn' Resources Now Supported
  56. QuickDraw now supports 16-bit and 32-bit per pixel 'cicn' resources.  The 16-bit per pixel is particularly cool since you save the space required for an 8-bit 'clut'.
  57. GWorlds Can Now Be Allocated in MultiFinder Temporary Memory
  58. You can now use the new useMFTempBit (bit 2) in a call to NewGWorld as an option to allocate pixels in MultiFinder temporary memory.  In addition, you can now allocate screen buffers in MultiFinder temporary memory using the following routine, defined in Pascal and C:
  59. FUNCTION NewTempScreenBuffer (globalRect: Rect; purgeable: BOOLEAN;
  60.                               VAR gdh: GDHandle;
  61.                                VAR offscreenPixMap: PixMapHandle): QDErr;
  62.              INLINE $203C,$000E, $0015,$AB1D; { Move.L #$000E0015,D0
  63.                                                _QDOffscreen
  64.                                              }
  65. pascal QDErr NewTempScreenBuffer (Rect *globalRect, BOOLEAN purgeable,
  66.                               GDHandle *gdh,
  67.                               PixMapHandle *offscreenPixMap)
  68.              ={0x203C,0x000E,0x0015,0xAB1D}; 
  69. Indexed to Indexed Dithering
  70. _CopyBits now supports the ditherCopy transfer mode whenever the destination device is between one and eight bits per pixel, regardless of the depth of the source image.  With this support, an eight-bit image can now be approximated on a one-bit or a four-bit device by using error diffusion.  Furthermore, an eight-bit image could also be dithered to a different set of 256 colors or a four-bit image could be dithered to an eight-bit device that does not have the desired colors.
  71. 32-Bit Addressed PixMap Structures
  72. Version 1.2 defines a new pmVersion (baseAddr32 = 4) for 32-bit pointer baseAddr values.  The baseAddr of such PixMap structures is treated as a 32-bit address, so no stripping or address translation is performed on it in 32-bit mode.  This is a specially useful feature when the base address of a PixMap points to a NuBus™ address, for example in a video grabber board.
  73. A new call, Pixmap32Bit, is now available to inquire if a given PixMap requires 32-bit addressing.
  74. FUNCTION Pixmap32Bit(pmh:pixMapHandle):Boolean;
  75.     INLINE $203C,$0004, $0016,$AB1D; { Move.L #$00040016,D0
  76.                                       _QDOffscreen
  77.                                     }
  78. pascal BOOLEAN Pixmap32Bit(pixMapHandle pmh)
  79.     = {0x203C,0x0004, 0x0016,0xAB1D}; 
  80. Updated GetPixBaseAddress
  81. Version 1.2 updates GetPixBaseAddress to return the address of any PixMap.  The routine does the right address translation or stripping for all PixMap structures, including screen devices, unlocked GWorlds, and 32-bit addressed PixMap structures.  The address it returns is only valid in 32-bit addressing mode. Also unless the PixMap is locked and made unpurgeable, the address returned by GetPixBaseAddress is only valid until any call to QuickDraw or the toolbox is made.
  82. _CopyBits from Screen Devices
  83. The picture recording mechanism has changed so that if you call _CopyBits while recording a picture with the source PixMap being a screen device, the data is correctly accumulated into the picture.  Note that if the screen being copied is not the main screen, then the PixMap must be a 32-bit addressed PixMap.  No auxiliary screen buffer is allocated if the source rectangle covers only one screen.
  84. New Picture Recording Trap
  85. Version 1.2 adds a new call, _OpenCPicture, to create pictures that contain information regarding the native resolution of the recorded image.  When QuickDraw draws this picture, it scales the image to the resolution of the target device.  Applications that need to scale the images directly can also access this information.
  86. FUNCTION OpenCPicture(VAR CPictInfo:CPictRecord):PicHandle;
  87.     INLINE $AA20;
  88. pascal PicHandle OpenCPicture(CPictRecord *CPictInfo)
  89.     =  0xAA20;
  90. where
  91. struct CPictRecord {
  92.       Rect CPicFrame;           /* Bounding rect of Picture at native resolution */
  93.       Fixed CPicHRes;           /* native horizontal resolution in pixels/inch   */
  94.       Fixed CPicVRes;           /* native vertical resolution in pixels/inch     */
  95.       short CPicVersion;        /* version of this PICT info set to -2           */
  96.       short reserved;           /* for future expansion set to zero              */
  97.       long reserved;            /* for future expansion set to zero              */
  98.         };
  99. The new picture header data looks like the following:
  100. Size in bytes    Name    Description
  101.     2    picSize    low word of picture size
  102.     8    picFrame    bounding box at 72 dpi
  103. Picture Header
  104. 2    version op    version opcode = $0011
  105. 2    version    version number = $02FF
  106. 2    Header op    header opcode  = $0C00
  107. 2    version    -2 for PICTs created with _OpenCPicture
  108. 2    reserved
  109. 4    HRes    native horizontal resolution (Fixed)
  110. 4    VRes    native vertical resolution (Fixed)
  111. 8    SrcRect    native source rectangle
  112. 4    reserved
  113. The following is a sample PICT created with _OpenCPicture:
  114.     00 48                          /* low word of size              */
  115.     00 00 00 00 00 7D 00 7D        /* picFrame at 72 dpi            */
  116.     00 11                          /* PICT version opcode           */
  117.     02 FF                          /* version number                */
  118.     0C 00                          /* PICT header Opcode            */
  119.     FF FE                          /* PICT version -2               */
  120.     00 00                          /* reserved                      */
  121.     01 20 00 00                    /* HRes (Fixed)                  */
  122.     01 20 00 00                    /* VRes (Fixed)                  */
  123.     00 00 00 00 01 F4 01 F4        /* picFrame at native resolution */
  124.     00 00 00 00                    /* reserved                      */
  125.     /* picture data follows                                         */
  126.     00 FF                          /* end of picture opcode         */
  127. Random Notes
  128. For information on bug fixes in the System Software 6.0.5 release of 32-Bit QuickDraw (version 1.2), please refer to the System Software 6.0.5 Change History, which is available on the Developer CD Series, AppleLink in the Developer Services Bulletin Board (Developer Services: Macintosh Developer Technical Support: System Software), and the Apple FTP site on the Internet in the ~ftp/pub/dts/sw.license.
  129. Note that the dispatching mechanism for the new _QDOffscreen calls is slightly different than previously documented; it now requires that the high word passed in D0 contain the total length of the parameters (in bytes).  The reason for this change is that if the call is made in an earlier version of 32-Bit QuickDraw, the system can strip the parameters from the stack and return QDError set to the caller (instead of crashing).
  130. Further Reference:
  131. •    Inside Macintosh, Volume V, Color QuickDraw
  132. •    32-Bit QuickDraw Release Notes (available from APDA)
  133. •    System Software 6.0.5 Change History
  134. •    d e v e l o p, Issue I
  135. NuBus is a trademark of Texas Instruments.
  136. Basic QuickDraw Q&As
  137. Imaging    M.IM.BasicQD.Q&As
  138. Revised by:    Developer Support Center    October 1992
  139. Written by:    Developer Support Center    October 1990
  140. This Technical Note contains a collection of Q&As relating to a specific topic—questions you’ve sent the Developer Support Center (DSC) along with answers from the DSC engineers. While DSC engineers have checked the Q&A content for accuracy, the Q&A Technical Notes don’t have the editing and organization of other Technical Notes. The Q&A function is to get new technical information and updates to you quickly, saving the polish for when the information migrates into reference manuals.
  141. Q&As are now included with Technical Notes to make access to technical updates easier for you. If you have comments or suggestions about Q&A content or distribution, please let us know by sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical questions about Q&A content to DEVSUPPORT for resolution.
  142. New Q&As and Q&As revised this month are marked with a bar in the side margin.
  143. Sending PostScript via PostScriptHandle PicComment
  144. Written:    5/1/90
  145. Last reviewed:    10/9/91
  146. If I use the PostScriptHandle PicComment to send PostScript code to the LaserWriter driver, do I need to open a picture and then draw the picture to the driver, or can I just use the PicComment with no picture open while drawing to the printer’s grafPort?
  147. ___
  148. You don’t need to create a picture with your PicComment in it and draw the picture to the driver. The best method for sending PostScript code to the LaserWriter is to use the PostScriptHandle PicComment documented in the Macintosh Technical Note #91, “Optimizing for the LaserWriter—Picture Comments,” as shown below.
  149. PrOpenPage(...)
  150. { Send some QuickDraw so that the Printing Manager gets a }
  151. { chance to define the clipping region. }
  152. PenSize(0,0); 
  153. MoveTo(0,0);
  154. LineTo(0,0); 
  155. PenSize(1,1); 
  156. PicComment(PostScriptBegin, 0, NIL);
  157. { QuickDraw representation of graphic. }
  158. MoveTo(100, 100);
  159. LineTo(200, 200);
  160. { PostScript representation of graphic. }
  161. thePSHandle^^ := '100 100 moveto 200 200 lineto stroke';
  162. PicComment(PostScriptHandle, GetHandleSize(thePSHandle),
  163.               thePSHandl);
  164. PicComment(PostScriptEnd, 0, NIL);
  165. PrClosePage(...)
  166. The above code prints a line on any type of printer, PostScript or not. The first MoveTo/LineTo combination is required to give the LaserWriter driver a chance to define a clipping region. The LaserWriter driver replaces the grafProcs record in the grafPort returned from PrOpenDoc. In order for the LaserWriter driver to get execution time, you must execute a QuickDraw drawing routine that calls one of the grafProcs. In this case, the MoveTo/LineTo combination calls the StdLine grafProc. When StdLine executes, it notices that the grafPort has been reinitialized, and therefore initializes the clipping region for the port. Until the MoveTo/LineTo combination is executed, the clipping region for the port is set to (0,0,0,0). If PostScript code is sent via the PostScriptHandle PicComment before executing any QuickDraw routines, all PostScript operations will be clipped to (0,0,0,0).
  167. The next thing that’s done is to send the PostScriptBegin PicComment. This comment is recognized only by PostScript printer drivers. When the driver receives this comment, it saves the current state of the PostScript device (by executing the PostScript gsave operator), then disables all QuickDraw drawing operations. This way, the QuickDraw representation of the graphic will be ignored by PostScript devices. In the above example, the second MoveTo/LineTo combination is executed only on non-PostScript devices.
  168. The next PicComment is PostScriptHandle, which tells the driver that the data in thePSHandle is to be sent to the device as PostScript code. The driver then passes this code unchanged to the PostScript device for execution. The PostScriptHandle comment is recognized only by PostScript printer drivers.
  169. The last PicComment, PostScriptEnd, tells the driver to restore the previous state of the device (via a PostScript grestore call), and to enable QuickDraw drawing operations.
  170. Since most PicComments are ignored by QuickDraw devices, only the QuickDraw representation is printed. Since PostScriptBegin tells PostScript drivers to ignore QuickDraw operations, only the PostScript representation is printed on PostScript devices. This is a truly device-independent method for providing both PostScript and QuickDraw representations of a document.
  171. Macintosh PICT-to-PostScript conversion
  172. Written:    8/3/90
  173. Last reviewed:    10/8/91
  174. How do I convert PICT format data to PostScript in my printer driver?
  175. ___
  176. Converting PICT files to PostScript involves a detailed understanding of both bitmaps (or pixmaps) and the graphics state in PostScript, which is a data structure defining the context in which other graphic operators in PostScript execute. If you don’t know PostScript, the following manuals are a must:
  177. • PostScript Language Tutorial and Cookbook (Addison-Wesley) is an introduction to PostScript. • PostScript Language Reference Manual (Addison-Wesley).
  178. • PostScript Language Program Design (Addison-Wesley) details designing efficient PostScript programs. It has a lot of useful sample programs on topics like writing a print spooler.
  179. You need to convert all the QuickDraw operations in a PICT to corresponding PostScript operations. To get a feel for this conversion, you can analyze the PostScript dump from a LaserWriter to see how it converts a PICT to PostScript. Under System 6.x, a PostScript dump can be obtained by pressing Command-K while printing. Under System 7.0, you can get a dump by selecting the PostScript File option in the Print dialog.
  180. Some areas of QuickDraw, such as transfer modes, do not have a correspondence in PostScript. The PostScript imaging model is designed so that all areas of a page affected by an image are marked as if with opaque paint. Using image masks can help. See the Graphics chapter in the PostScript reference manual.
  181. PICT-to-PostScript conversion can be a long process, especially if one is unfamiliar with PostScript. Using the above books and the PostScript dump from the LaserWriter (but ONLY as a general guide) should help.
  182. Calling InitCursor instead of SetCursor
  183. Written:    10/23/90
  184. Last reviewed:    2/20/91
  185. Is it legal to call InitCursor instead of SetCursor(arrow) when I want to set the cursor to an arrow (after my normal one-time program initialization code, in my UpdateCursor routine)? The only reason I'd want to do such a skanky thing is to save code. Calling a trap with no parameters is less code than one with parameters. What, exactly, if anything, does InitCursor do besides setting the cursor to an arrow and setting the cursor level to zero?
  186. ___
  187. There's no problem at all with this, as long as you are aware that the hidden, busy, and obscured states are cleared when you call InitCursor, so if the cursor was hidden or obscured for good reason it'll suddenly reappear. It also gets the arrow from QuickDraw, of course, but that's not a problem.
  188. PICT fontName opcode
  189. Written:    10/31/90
  190. Last reviewed:    2/20/91
  191. Is there an up-to-date canonical source for PICT opcodes? In “Night of the Living Disc,” as far as I can see, the only list of PICT opcodes is in the Macintosh Tech Note “QuickDraw’s Internal Picture Definition” which does not mention opcode $2C. It appears that opcode $2C concerns font names. I recall seeing a patch for PictDetective named "fontnameop" or something like that. However I can't be sure that $2C is the only new opcode.
  192. ___
  193. The fontName opcode is documented in the Technical Note “32-Bit QuickDraw: Version 1.2 Features.” Note also that since the introduction of 32-Bit QuickDraw there are two more bitmap opcodes for direct RGB PixMaps $009A (DirectBitsRect) and $009B (DirectBitsRgn). The QuickDraw section of Inside Macintosh Volume VI has all these opcodes listed in a single place, making it easier to get the necessary info. Here is the info on font names and pictures from the "32-Bit QuickDraw..." Tech Note:
  194. PICTs Contain Font Name Information
  195. Every time you draw text inside of an _OpenPicture and _ClosePicture pair,
  196. QuickDraw stores the name of the current font and uses it when playing back
  197. the picture. The opcode used to save this information is $002C and its data is
  198. as follows:
  199.    PictFontInfo = Record
  200.                     length   : Integer;    { length of data in bytes }
  201.                     fontID   : Integer;    { ID in the source system }
  202.                     fontName : Str255;
  203.                   END;
  204. QuickDraw saves this information only one time for each font used in a picture. When QuickDraw plays back a picture, it uses the fontID as a reference into the list of font names which are used to set the correct font on the target system.
  205. For example, the following code:
  206.    GetFNum('Venice', theFontID);    { Set a font before opening PICT}
  207.    TextFont(theFontID);
  208.    pHand2 := OpenPicture (pictRect);
  209.        MoveTo(20,20);
  210.        DrawString(' Better be Venice');
  211.        GetFNum('Geneva', theFontID);
  212.        TextFont(theFontID);
  213.        MoveTo(20,40);
  214.        DrawString('Geneva');
  215.        GetFNum('New York', theFontID);
  216.        TextFont(theFontID);
  217.        MoveTo(20,60);
  218.        DrawString('New York');
  219.        GetFNum('Geneva', theFontID);
  220.        TextFont(theFontID);
  221.        MoveTo(20,80);
  222.        DrawString('Geneva');
  223.    ClosePicture;
  224. generates a picture containing font information like this:
  225.    OpCode 0x002C {9,
  226.        "0005 0656 656E 6963 65"}          /* save current font     */
  227.    TxFont 'venice'
  228.    DHDVText {20, 20, " Better be Venice"}
  229.    OpCode 0x002C {9,                      /* save next font name   */
  230.        "0003 0647 656E 6576 61"}
  231.    TxFont 'geneva'
  232.    DVText {20, "Geneva"}
  233.    OpCode 0x002C {11,                     /* ditto                  */
  234.        "0002 084E 6577 2059 6F72 6B"}
  235.    TxFont 'newYork'
  236.    DVText {20, "New York"}
  237.    TxFont 'geneva'                        /* second Geneva does not
  238.                                           need another $002C guy */
  239.    DVText {20, "Geneva"}
  240. This feature works regardless of the type of picture being saved, including old style PICTs in a black-and-white port. Using _OpenCPicture instead of _OpenPicture to start a recording session results in the same functionality.
  241. X-Refs:
  242. Inside Macintosh Volume VI
  243. Macintosh Technical Note “QuickDraw's Internal Picture Definition”
  244. Macintosh Technical Note “32-Bit QuickDraw: Version 1.2 Features”
  245. Using PicComments to rotate text
  246. Written:    11/28/90
  247. Last reviewed:    12/19/90
  248. I have a PostScript routine (using TextBegin/TextEnd) to generate bitmapped rotated text on the screen (which can be later printed on QuickDraw printers). Why do I get duplicate text? I get both bitmapped rotated text and PostScript rotated text when I print on the LaserWriter II, and both bitmapped rotated text and horizontal text on the ImageWriter. When I make a machine dependent check (check type of printer) and call the proper printing procedure, it works fine. Because of the speed and memory considerations of generating the rotated bitmapped text (especially at 300 dpi), is there a way to ensure that the printer will use the PostScript BEFORE generating the bitmap?
  249. ___
  250. We will use the following Macintosh PicComments to hide your QuickDraw calls from the LaserWriter, but the ImageWriter will use them:
  251. PostScriptBegin
  252.  >> Put your CopyBits and QuickDraw calls to image your rotated
  253.  >> bitmapped text here....
  254. PostScriptEnd
  255. By wrapping your QuickDraw code within the PostScriptBegin and PostScriptEnd PicComments, the code will be ignored by the LaserWriter, but the ImageWriter will use the QuickDraw calls. Basically, the PostScriptBegin and PostScriptEnd PicComments tell the LaserWriter driver to turn “off” QuickDraw. In the ImageWriter case, the ImageWriter does not understand the PicComments. Therefore, it will use the QuickDraw calls to create and image your bitmapped text. 
  256. Now, we need to use the rotation PicComments to rotate the text on the LaserWriter, but have the ImageWriter ignore the code:
  257. Rect  zeroRect;
  258. SetRect (&zeroRect, 0, 0, 0, 0);
  259. TextBegin
  260. TextCenter
  261.       ClipRect (&zeroRect);
  262.       >> Draw your text to be rotated on the LaserWriter....
  263.       ClipRect (&rPageRect);
  264. TextEnd
  265. Wrapping your text drawing call(s) between the ClipRect calls will ensure that the text is drawn only on the LaserWriter. Setting the ClipRect to zero tells the ImageWriter to ignore all QuickDraw calls until the ClipRect is reset to something “real” (actually, a zero ClipRect prevents QuickDraw from drawing anything). After we have completed drawing the rotated text, we reset the ClipRect to the dimensions of rPage (that is, rPage is the image-able area of the currently selected printer—see Inside Macintosh, Volume II, page 150). This will allow all of your normal drawing to continue on the ImageWriter and LaserWriter. If you did not reset the ClipRect after the TextEnd call, nothing would be drawn on the ImageWriter or LaserWriter.
  266. Using dithered drawing mode with QuickDraw
  267. Written:    11/28/90
  268. Last reviewed:    12/19/90
  269. When I draw a 32-bit Macintosh PICT image from a file to an 8-bit port via an offscreen GWorld, I use dither mode in the CopyBits call and the results are quite impressive. If there is not enough memory to allocate the GWorld, I draw the image directly to the port. But since there does not seem to be any way to tell QuickDraw to use dithered drawing mode, the image looks horrible.
  270. Do you have any suggestions? I have installed bottleneck procs to allow DrawPicture to get its data from the file instead of the handle in memory. Is there a way, while in the bottlenecks, to find the CopyBits call that comes from the picture and force it to use dithered mode instead of source mode? I don’t want to try and parse the PICT myself, but I thought that maybe a QuickDraw global could be modified in my StdBits proc to force dithered drawing for that operation only?
  271. ___
  272. You can install a StdBits or bitsProc bottleneck procedure to get all the CopyBits calls when the picture is being played back. One of the parameters to the StdBits call is the mode. You can install a procedure that saves the current mode, and then passes ditherMode to the original StdBits proc. This is all you should need to do. It’s been done here so we know it works, only not in any form that can be sent to you as sample code at this time.
  273. Code for reversing Macintosh PICT images
  274. Written:    3/4/91
  275. Last reviewed:    8/30/91
  276. Is there a simple way to put PICT images up in mirror image format, or is there sample code showing how to flip an offscreen bitmap?
  277. ___
  278. There is no easy way to do this, nor do we have sample code showing how to flip an offscreen bitmap. Indeed, the best way to do what you want is to draw it to an offscreen pixel map and reverse it.
  279. If you are using Color QuickDraw, always draw it to an 8-bit-per-pixel offscreen bitmap, and then the reverse is a very simple task. Here is some sample Pascal code that might roughly do what you want, with the following assumptions:
  280.     1. You are going to add error checking where appropriate.
  281.     2. Rowbytes correspond exactly to pixel width of the port.
  282.     3. The port is 8 bits deep.
  283.     4. You add the code to make this sketch work.
  284.     5. The origin of your offscreen port is (0,0).
  285. Procedure FlipScanLine(theV:Integer; thePort:cGrafPtr);
  286. { Given any scan line number in the indicated port, this routine will flip }
  287. { that scan line horizontally. This routine assumes that you have made     }
  288. { sure that scan line theV exists. }
  289. type ScanLn=Packed Array [0..0] of Byte;
  290.    ScanPtr=^ScanLine;
  291. var thePixMap:PixMapPtr;
  292.    Index,Size:Integer;
  293.    ThisScanLine:ScanPtr;
  294.    TempPixel:Byte;
  295. Begin
  296.  thePixMap:=thePort^.PortPixMap^;
  297. { First create a pointer to the scan line we are currently reversing. }
  298.  ThisScanLine:=ScanPtr(thePixMap^.BaseAddr);
  299.  ThisScanLine:=ScanPtr(ord4(ThisScanLine)+(thePixMap^.RowBytes*theV));
  300. { Now simply reverse all the bytes. }
  301. { The scan line is simply an array [0..RowBytes] of Byte, and since this is }
  302. { 8 bits per pixel, each one is a single pixel.}
  303.  Size:=thePixMap^.RowBytes;
  304.  For Index:=0 to (Size div 2) do
  305.   begin
  306.    tempPixel:=ThisScanLine^[Index];
  307.    ThisScanLine^[Index]:=ThisScanLine[Size-Index-1];
  308.    ThisScanLine^[Index]:=tempPixel;
  309.   end;
  310. end;
  311. This same procedure can be used also to swap a 1-, 2- or 4-bit-per-pixel pixmap if you add a function that accepts a byte and swaps the pixels in it.
  312. Use srcOr instead of srcCopy for Macintosh text drawing
  313. Written:    6/4/91
  314. Last reviewed:    10/9/91
  315. DrawText with srcCopy takes six times as long as with srcOr now that my Macintosh is running System 7. Why is this so slow? Is this a bug in System 7?
  316. ___
  317. It’s true that srcCopy is slower than srcOr when handling text, especially in color mode. This loss in speed occurs because CopyBits is a lot smarter than it used to be. It can handle foreground and background colors a lot better, but that improvement came at the cost of speed. Our recommended method for drawing text is to erase before drawing, and use srcOr to draw, not srcCopy. Alternatively, you could draw colorized text in srcOr mode off screen and then use CopyBits to draw it on the screen in srcCopy mode without colorization.
  318. Techniques for graying Macintosh text
  319. Written:    6/3/91
  320. Last reviewed:    8/1/91
  321. How do I draw grayed-out text on the Macintosh, like the text for disabled buttons or menu items?
  322. ___
  323. There are currently two different kinds of grayed text: First, there’s 
  324. “patterned” gray, where every other dot is missing. This really only looks good with Chicago or other heavy fonts and was always used for graying out menus and controls in system software through 6.0.x, and is still used in 7.0 when the screen is set to less than 4 bits deep. This is done by first drawing the text in a normal, srcCopy transfer mode. Then a gray rectangle is drawn over the text using the patBic mode. This “erases” half the bits in the text, and is rapid enough that there is very rarely any flicker.
  325. The second kind of text is the actually gray text, which is used in System 7 on screens that are 4 bits deep or deeper for menus, controls, and other grayed text. To draw this text, just call GetGray (as documented on page 17-27 of Inside Macintosh, Volume VI) to get an appropriate gray. Then draw the text in that color.
  326. Updating Macintosh cursor without mouse competition
  327. Written:    6/12/91
  328. Last reviewed:    8/1/91
  329. How can I programmatically move the Macintosh mouse without the real mouse interfering?
  330. ___
  331. The real answer to your question is twofold: First, you can do exactly what you want to do with the sample included below. HOWEVER, this is not a good thing to do, it would be better if you took the solution used in Apple’s Guided Tour disks: Always hide the cursor and then decouple the cursor from the mouse. Then, instead of using the system’s cursor, simply draw your own “cursor” using QuickDraw and treat it as a little animated bitmap on the screen. This avoids all the problems that you have with the mouse competing. (Apple does update the mouse globals with the mouse position so that other things function correctly.)
  332. Now, as promised, here is the way to do what you want using the real cursor. As you have discovered, setting the crsrCouple variable to false prohibits the mouse from affecting the cursor; unfortunately, it also prohibits the jcrsrTask routine from drawing the cursor. The solution to this is to set crsr couple to true, call the cursor drawing routine jCrsrTask yourself, and then set the crsrCouple variable to false, as shown below:
  333. procedure callcrsr;
  334.               inline $2078 ,$08EE ,$4E90;
  335. {            move.L    jcrsrTask,A0
  336.             jsr    (A0)                            }
  337. Procedure FudgeMouse;
  338. type    PointPtr=^Point;
  339. var        RawMouse:PointPtr;
  340.         MTemp:PointPtr;
  341.         RandPt:Point;
  342.         CrsrNew:ptr;
  343.         CrsrCouple:ptr;
  344.         fred:Longint;
  345.        
  346. begin
  347.         RawMouse:=PointPtr($82C);
  348.         MTemp:=PointPtr($828);
  349.         CrsrNew:=ptr($8CE);
  350.         CrsrCouple:=ptr($8CF);
  351.         RandPt:=RawMouse^;
  352.         repeat
  353.             RandPt.h:=RandPt.h+1;
  354.             RandPt.V:=RandPt.v+1;
  355.             RawMouse^:=RandPt;
  356.             MTemp^:=RandPt;
  357.             CrsrNew^:=1;
  358.             CrsrCouple^:=1;
  359.             callCrsr;
  360.             crsrCouple^:=0;
  361.             repeat until fred<tickCount;
  362.             fred:=tickCount+3;
  363.         until Button;
  364.         crsrCouple^:=1;
  365. end;
  366. System 7 QuickDraw DrawText performance
  367. Written:    11/4/91
  368. Last reviewed:    11/27/91
  369. We’ve noticed that using DrawText is much slower in System 7, especially when drawing in color (anything other than black on white). What can be done to restore the drawing speed to System 6 levels?
  370. ___
  371. A QuickDraw function like DrawString or DrawText will be slower under certain circumstances in System 7 than System 6. Specifically, if you are drawing in srcCopy mode and you colorize the text—that is, foreground color is not black and background color is not white (Inside Macintosh Volume VI, page 17-16)—then QuickDraw really slows down as you have noticed. SOMETIMES, the speed of drawing is 6 times as slow as System 6.
  372. The cause of this slowness is a known System 7 bug. The bug has concerned the engineers greatly and will be responded to in an appropriate manner in the future.
  373. There are a few workarounds: One, you can avoid using the srcCopy mode and use the default srcOr mode instead. However, this is not a real workaround, since you may have essential reasons to use srcCopy. The other option is to create an offscreen pixmap or GWorld and perform a DrawText with srcOr to this GWorld with colorization. Then, you can perform a CopyBits from the offscreen to the screen with srcCopy mode and no colorization. Using CopyBits will not cost you much time. Again, this is a workaround and is not ideal. 
  374. The srcOr is a bit slower than in System 6.0.x, but it does not have a bug; rather it is a side effect of system enhancements. The slow speed is a trade-off taken to receive the host of other benefits.
  375. Macintosh animation samples
  376. Written:    11/6/91
  377. Last reviewed:    11/6/91
  378. Do you have an example of flicker-free animation on the Macintosh?
  379. ___
  380. We have some good stuff that’s written in MPW Pascal. It’s DTS Sample Code #16, OffSample, and this uses some routines defined in DTS Sample Code #15, OffScreen. Also, the System 7.0 CD sample code folder contains a smaller sample called “GMonde” that uses GWorlds.
  381. CopyBits bug and workaround
  382. Written:    6/26/91
  383. Last reviewed:    8/13/91
  384. Has anyone run across what I’m told is a bug in CopyBits? It works like this: In the deep, dark workings of CopyBits, some routine tries to read the two bytes preceding the baseAddress of the source PixMap. If the baseAddress is at the start of a card’s NuBus space and there isn’t a card filling the adjacent space, this causes a bus error! Has anyone found a good workaround?
  385. ___
  386. The short answer is: you’re right. QuickDraw inadvertently reads from memory below the base address of a pixmap. The workaround is to place the video base address 32 bytes into the RAM on the card; if the card you’re using doesn’t have this workaround, there’s nothing you can do other than making sure there’s a card in the next-lower slot.
  387. Macintosh picture (PICT) 90-degree rotation
  388. Written:    7/23/91
  389. Last reviewed:    8/30/91
  390. The trick for rotating a Macintosh QuickDraw picture 90 degrees is to intercept all bottlenecks and exchange the x and y coordinates. Then, call OpenPicture to receive the rotated picture, call DrawPicture(unrotatedPicture), and then call ClosePicture on the rotated picture. You’re done! QuickDraw spins out the DrawPicture call into its component parts, but runs each component through the bottlenecks first, so they get rotated (by YOUR bottleneck intercepts) and stuck into the new picture, already rotated.
  391. Here‘s a bottleneck intercept for StdLine that rotates a PICT composed entirely of Line commands (which depend on the current pen position):
  392. procedure MyLineProc(newPt: point);
  393. var
  394.   tempV : integer;
  395. begin
  396.   tempV := thePort^.pnLoc.v;     { Swap current pen location coordinates }
  397.   thePort^.pnLoc.v := thePort^.pnLoc.h;
  398.   thePort^.pnLoc.h := tempV;
  399.   
  400.   tempV := newPt.v;          { Swap destination pen location coordinates }
  401.   newPt.v := newPt.h;
  402.   newPt.h := tempV;
  403.   
  404.   StdLine(newPt);
  405.   
  406.   tempV := thePort^.pnLoc.v;  { Restore current pen location coordinates }
  407.   thePort^.pnLoc.v := thePort^.pnLoc.h;
  408.   thePort^.pnLoc.h := tempV;
  409. end;
  410. Notice that the start coordinates as well as the destination coordinates must be swapped before calling StdLine. The resulting pen location is swapped back again after the operation, so the port looks like it should if unrotated drawing were performed. For things that don’t depend on the current pen location, things are simplified a little bit.
  411. You’ll still need bitmap rotation code for the StdBits and StdText intercepts.You might do StdText by setting the port to an offscreen one you create earlier, calling QuickDraw’s StdText, and then calling your bitmap rotation code to copy it into the destination.
  412. Macintosh QuickDraw and pen characteristic routines
  413. Written:    8/12/91
  414. Last reviewed:    11/6/91
  415. When generating pictures and then looking at the corresponding Macintosh PICT file, we notice that QuickDraw is optimizing PnMode, PnPat, and PnSize. Can you tell us how to stop QuickDraw from optimizing, and how to know when QuickDraw will optimize?
  416. ___
  417. QuickDraw does not optimize away new pen characteristic routines, but it does insert them into pictures just before a drawing routine that uses the pen rather than place them where they are called. Therefore, you may not see your new pen characteristic routine until later in a picture when it is about to be used. Opcodes for pen characteristics are inserted into the picture when they are changed from the previous time they’re used.
  418. Detecting whether application window is partially hidden
  419. Written:    9/26/92
  420. Last reviewed:    1/27/92
  421. We draw directly to the screen to gain the fastest possible animation speed, and when we need compatibility—such as when windows overlap or for multiple screens—we do use CopyBits. How do we tell whether the window is hidden or that the visible part is not rectangular?
  422. ___
  423. If your window is covered partially by another applications window or if your layer has been hidden by the process menu, the visRgn of your window’s grafport will not be the portRect anymore. (Keep in mind that if you scroll by modifying the portRect of the grafport, then you’ll have to do a more complex calculation...) Here is a small Pascal routine that returns this information:
  424. Function UseCopyBits(thePort:grafptr):Boolean;
  425. begin
  426.    
  427.      UseCopyBits:= NOT( (thePort^.VisRgn^^.rgnSize=10) and
  428.         (thePort^.visRgn^^.RgnBBox=thePort^.PortRect) );
  429. end;
  430. The rect strucRgn^^.rgnBBox will be zero for a visible window if the system 
  431. has hidden the application.
  432. How to tell whether GetPictInfo is available
  433. Written:    12/16/91
  434. Last reviewed:    2/24/92
  435. How do you determine whether the function GetPictInfo is available? Gestalt doesn’t seem to have the right stuff?!
  436. ___
  437. To determine whether the GetPictInfo routine is available, check the system version number with the Gestalt function. The GetPictInfo routine is available under system software version 7.0 and later. Use the Gestalt selector gestaltSystemVersion to determine the version of the system currently running. In most cases you shouldn’t rely on the system version to determine if features are available. However, in this case, this is the only way to determine if the Picture Utilities Package is available.
  438. See Inside Macintosh Volume VI page 3-42 for information on using Gestalt to check the System version number. See Inside Macintosh Volume VI page 18-3 for information on the Picture Utilities Package.
  439. For example, the following C function will determine if the GetPictInfo call is available:
  440.     #include <GestaltEQU.h>
  441.     Boolean IsGetPictInfoAvail()
  442.     {
  443.       OSErr err;
  444.       long feature;
  445.          err = Gestalt(gestaltSystemVersion,&feature);
  446.       /*-- check for system 7 and above --*/
  447.       return (feature >= 0x00000700);
  448.     }
  449. or, if you prefer Pascal:
  450.     function IsGetPictInfoAvail: Boolean;
  451.     var
  452.         err: OSErr;
  453.         feature: longint;
  454.     begin
  455.         err := Gestalt(gestaltSystemVersion, feature);
  456.         (*-- check for system 7 and above --*)
  457.         IsGetPictInfoAvail := (feature >= $00000700);
  458.     end;
  459. GrafPort patStretch: valid values
  460. Written:    12/19/91
  461. Last reviewed:    2/6/92
  462. I’d like to know more about that PatStretch field inside a GrafPort or CGrafPort. If I stuff a values in PatStretch(4) then nothing happens; prints look the same, even using a standard bottleneck. Please tell me how I can get this to work.
  463. ___
  464. PatStretch only works with values of 2 or 3. With any other value, it defaults to no stretching. The “2” case was created because of the ImageWriter (72->144 dpi) situation. The “3” case was added to support the ImageWriter LQ and the AppleFax modem.
  465. So why wasn’t a “4” (72->300 dpi) handler added for the LaserWriter driver? Good question. Somehow or other it was decided that pattern stretching for the LaserWriter driver would be done completely by the driver itself. The LaserWriter driver actually does pattern stretching by using a pattern 4 times as large, rather than 4.17. In other words, it really scales the 72 dpi pattern to 288 dpi rather than 300 dpi. You may want to take a similar approach, since you’d only have to work with whole numbers this way.
  466. So, if you want to do 4-times pattern stretching, you must scale the pattern yourself. If you copy the original pattern into an area that’s twice as wide and twice as tall and use that, you should be all set. You’ll need to use PrGeneral to set the printer to the appropriate resolution and Copybits to copy the pattern into the object that needs to be filled, using the “cookie cutter” approach to fill the object.
  467. X-Ref:
  468. Inside Macintosh Volume I, page I-150
  469. Where CopyBits looks for memory to use
  470. Written:    1/3/92
  471. Last reviewed:    1/27/92
  472. Where does CopyBits look for the memory it needs?
  473. ___
  474. CopyBits checks the stack to determine if there is enough stack space for it to copy the whole image, which in some cases may be roughly up to 5 extra rowbytes of special effects per row, depending on what special effects such as dithering or scaling are being used. If there is not enough stack space for the whole image, CopyBits then tries for half the image, and keeps halving until it gets down to one row of the image (plus the room for the special effects rows). If there is not enough stack space for one row of the image, then CopyBits tries to allocate temporary memory.
  475. Before allocating temporary memory, CopyBits checks if the temporary memory traps are available. (They are available under both System 6 MultiFinder and System 7.) If the traps are available, CopyBits tries to allocate a 256K byte buffer for use as a “fake” stack. (CopyBits used to try for a 64K block, but this has been changed, and it may change again.) If this succeeds, then all is well and the image is copied. If the temporary memory traps do not exist, or if CopyBits cannot allocate a 256K buffer, then the image is not copied and CopyBits returns.
  476. CopyBits does not check in the application heap for free memory, at least not for its work buffer. For its work buffer it will only use the stack, and after that it resorts to temporary memory, if available. There are some circumstances that may cause memory allocations in the application heap, but this memory is not used for CopyBits’s image buffer.
  477. Also, please note that the implementation of CopyBits is subject to change in future versions of QuickDraw.
  478. PICTs with PostScript PICT comments and memory use
  479. Written:    1/10/92
  480. Last reviewed:    2/17/92
  481. Why does my PICT (including dotted lines) use so much memory when drawn in MacDraw, and even more when drawn in SuperPaint? Do they include PicComments for PostScript?
  482. ___
  483. Your guess that it has to do with PicComments is quite right; both MacDraw and SuperPaint include a PostScript representation of the dotted (dashed) lines and some other graphic operations in the PICT, together with the QuickDraw commands. During printing, this allows the LaserWriter driver to take advantage of specific PostScript capabilities that are unavailable in QuickDraw, like primitives for dashed lines.
  484. On the other hand, the PostScript representation for dashed lines is much shorter than the QuickDraw representation, which requires a (long, very long …) sequence of “ShortLine” opcodes. So, another piece of explanation for the large PICT size basically is that QuickDraw does not have facilities to describe dotted lines in an economic way.
  485. SuperPaint also includes a copy of a proprietary dictionary, which adds substantially to the size of a PICT. On the other hand, the code that resides in that dictionary makes the picture’s PostScript representation that much better. Ultimately, WYSIWYG is the goal, and sometimes it takes a little extra code to make that happen. (Incidentally, the PostScript dictionary contained in pictures created by older versions of SuperPaint makes assumptions about the contents of the LaserPrep file which are not true for the recent versions of the LaserWriter driver. Documents containing such pictures will not print correctly any more.)
  486. To determine the primitives that define other nonstandard QuickDraw objects found in drawing applications, you can use MPW’s DeRez function or a third-party utility such as Palomar Software’s PICT Detective on the resource PICT. These tools will provide the opcodes that define the PICT.
  487. Inside Macintosh Vol. V PICT opcode size should be fixed
  488. Written:    1/22/92
  489. Last reviewed:    2/28/92
  490. The definition of PICT version 2 on pages 92-105 of Inside Macintosh Volume V says that the data size of the opcodes $001A and $001B is variable, but also that the data is an RGBColor. This is confusing, since the size of an RGBColor is fixed at six bytes. How can these two opcodes vary in the amount of associated data?
  491. ___
  492. Seems like you’ve run into a cut/paste problem. All the opcodes that refer to table 4 are new for Color QuickDraw. Also, most of them are variable in length, so the author simply had a standard notation for anything that was explained further in table 4 (page V-103). The information contained in table 4 is, in fact, accurate. The size information of several of the opcodes listed is not variable even though the preceding pages told you they were.
  493. All you gotta do is believe table 4 and you will be fine.
  494. Code for filling an area fully bounded by polygon
  495. Written:    2/21/92
  496. Last reviewed:    6/11/92
  497. Currently, when a polygon is filled, an even-odd rule is applied to determine which areas of the polygon are to be filled. For our application, we also need to fill all the areas of the defined polygon. Is there a relatively easy way to accomplish this?
  498. ___
  499. There are many different ways to fill polygons, as you may know. If you do not want to use QuickDraw’s standard FillPoly routine, you’ll have to create your own. The following sample illustrates one technique that might be used to fill the area fully bounded by a polygon. It can be dropped right into the traffic light sample (sample.p) that ships with MPW as a replacement for its DrawWindow procedure. The green star is drawn using FillPoly and the black star is drawn using my filling technique that uses an offscreen bitmap and calcMask to fill in the poly the desired way, then CopyBits to transfer it to the onscreen port. The drawbacks of this method are that it is not as fast as writing a specialized poly routine; the benefits are that it’s small, fast enough for most operations, and can be used for more than just polygons.
  500. {$S Main}
  501. PROCEDURE DrawWindow(window: WindowPtr);
  502. var        MyPoly:PolyHandle;
  503.         MyRgn :RgnHandle;
  504.         OffPort,OnPort:GrafPtr;
  505.     Function    CreateOffport(VAR newOffscreen:grafPtr; 
  506. inBounds:Rect):Boolean;
  507.     var    SavePort,NewPort:Grafptr;
  508.     begin
  509.         GetPort(SavePort);
  510.         NewPort:=GrafPtr(NewPtr(sizeof(grafport)));
  511.         If MemError<>noErr then Begin
  512.             CreateOffport:=false;
  513.             EXIT(CreateOffport);
  514.         END;
  515.        
  516.         OpenPort(newPort);
  517.         With newPort^ do begin
  518.             portRect :=Inbounds;
  519.             RectRgn(ClipRgn,inBounds);
  520.             RectRgn(visRgn, inBounds);
  521.         End;
  522.        
  523.         With newPort^.PortBits DO BEGIN
  524.             Bounds:=Inbounds;
  525.             rowBytes:= ((inBounds.right-inBounds.Left+15) DIV 16) *2;
  526.             baseAddr:= NewPtr(rowBytes 
  527.                             * LONGINT(inBounds.Bottom-inBounds.Top));
  528.         End;
  529.         If MemError <>noErr THEN BEGIN
  530.             SetPort(SavePort);
  531.             ClosePort(newPort);
  532.             DisposPtr(ptr(newPort));
  533.             CreateOffport:=false;
  534.           END
  535.         ELSE  BEGIN
  536.             EraseRect(inBounds);
  537.             newOffscreen :=newPort;
  538.             setPort(SavePort);
  539.             CreateOffPort:=true;
  540.         end;
  541.     end;
  542.    
  543.     Procedure    KillOffPort(oldOffscreen :GrafPtr);
  544.     Begin
  545.         ClosePort(oldOffscreen);
  546.         DisposPtr(OldOffscreen^.portBits.baseAddr);
  547.         DisposPtr(ptr(OldOffScreen));
  548.     End;
  549. BEGIN
  550.     If NOT (CreateOffPort(offPort,window^.portRect)) THEN Exit(DrawWindow);
  551.     If NOT (CreateOffPort(onPort,window^.portRect)) THEN Exit(DrawWindow);
  552.    
  553.     SetPort(window);
  554.     MyRgn:=NewRgn;
  555.     OpenRgn;
  556.         MoveTo(10,25);
  557.         Lineto(70,25);
  558.         Lineto(15,70);
  559.         Lineto(40,10);
  560.         Lineto(65,70);
  561.         Lineto(10,25);
  562.     CloseRgn(MyRgn);
  563.     MyPoly:=OpenPoly;
  564.         MoveTo(10,25);
  565.         Lineto(70,25);
  566.         Lineto(15,70);
  567.         Lineto(40,10);
  568.         Lineto(65,70);
  569.         Lineto(10,25);
  570.     ClosePoly;
  571.     OffsetPoly(MyPoly,0,100);
  572.     SetPort(OffPort);
  573.     FramePoly(MyPoly);
  574.     { Now "Fill the poly" the right way }
  575.     CalcMask(    Offport^.portBits.BaseAddr,OnPort^.portBits.BaseAddr,
  576.                 OffPort^.portBits.RowBytes, OnPort^.portBits.RowBytes,
  577.                 OffPort^.portRect.bottom-OnPort^.portRect.Top,
  578.                 OffPort^.portBits.RowBytes DIV 2);
  579.     SetPort(OnPort);
  580.     SetPort(Window); 
  581.     If gStopped then
  582.         CopyBits(    OnPort^.portBits, Window^.portBits,
  583.                     OnPort^.portRect, Window^.portRect, srcCopy, NIL)
  584.     ELSE
  585.         CopyBits(    OffPort^.portBits, Window^.portBits,
  586.                     OffPort^.portRect, Window^.portRect, srcCopy, NIL);
  587.     IF gStopped THEN
  588.       begin
  589.         ForeColor(greenColor);
  590.         FrameRgn(MyRgn);
  591.       end
  592.     ELSE
  593.       begin
  594.         ForeColor(greenColor);
  595.         PaintRgn(MyRgn);
  596.       end;
  597.     ForeColor(blackColor);
  598.     DisposeRgn(MyRgn);
  599.     KillPoly(MyPoly);
  600.     KillOffPort(Offport);
  601.     KillOffPort(OnPort);
  602. END; {DrawWindow}
  603. Use crsrNew flag to unobscure cursor without mouse move
  604. Written:    3/3/92
  605. Last reviewed:    6/11/92
  606. The Macintosh QuickDraw routine ObscureCursor hides the cursor until the next time the mouse is moved but isn’t affected by HideCursor or ShowCursor. Our application needs to use ObscureCursor while the user is typing but needs the cursor to be visible after no typing has occurred for a short period. How do we “undo” ObscureCursor, since we can’t rely on the user moving the mouse?
  607. ___
  608. The only way to unobscure the cursor is to convince the system that the mouse has moved again. There is no real good way to do this via tool calls, so you are going to have to do it the hard way and simply update the low-memory cursor information to tell the system the cursor moved (even though you do not need to update the actual position).
  609. To tell the system the cursor has changed location, you simply set the crsrNew flag to 1; crsrNew is a byte located at $08CE. When the system sees this byte is 1 it will assume the cursor has moved, unobscure it, redraw at the appropriate place (where it was all along...) and reset crsrNew waiting for the mouse to move again, as in the following C and Pascal examples:
  610. /* the C version... */
  611. void UnObscureCursor ( void )
  612. {
  613.    *(char *)0x8CE = 1;
  614. }
  615. (* the pascal version *)
  616. Procedure UnObscureCursor;
  617. begin
  618.    ptr($08CE)^:=1;
  619. end;
  620. This will do what you want in a short, easy-to-use package.
  621. Macintosh QuickDraw region quirks
  622. Written:    1/1/90
  623. Last reviewed:    11/21/90
  624. I’m working with regions, and I’m having problems with Macintosh QuickDraw trashing the heap and crashing, even though my regions are under 32K.
  625. ___
  626. There are some quirks in the current version of QuickDraw. Here are some the commonly-encountered problems:
  627. 1. When doing operations which use more than one region, sduch as UnionRgn, DiffRgn, XorRgn, or SectRgn, the sum of the sizes of the source regions must be less than 32K, regardless of the size of the resulting region.
  628. 2. FrameRgn will fail if it tries to frame a region bigger than 16K.
  629. 3. If CloseRgn fails, the internal region data is already corrupt; there is nothing you can do to recover. CloseRgn will also fail if there isn’t at least a 32K block of free space available.
  630. Here are some workarounds:
  631. 1. Keep regions small and not too complex. Keep track of the sizes of all regions so you can check the SUM of the sizes before calling a routine that has a 32K limit.
  632. 2. Keep 32K free, or allocate a 32K block and release it just before calling CloseRgn.
  633. Apple is working on these problems and expects to fix them in future versions of QuickDraw.
  634. How to get Macintosh QuickDraw arc endpoints
  635. Written:    1/1/90
  636. Last reviewed:    11/21/90
  637. Is there a way to obtain the endpoints of an arc drawn by the Macintosh QuickDraw arc routines, such as FrameArc and PaintArc?
  638. ___
  639. Given a rectangle R which frames the arc you wish to draw, convert your angles to an absolute coordinate system, where three o’clock is 0 degrees and 12 o’clock is 90 degrees.
  640. Now, let:
  641.     x = .5 (+ or -) (R.right - R.left)
  642.     y = .5 (+ or -) (R.bottom - R.top)
  643. The endpoint of the curve will be defined by:
  644.     EndPoint.h = x (+ or -) cos(ang);
  645.     EndPoint.v = y (+ or -) sin(ang);
  646. h & v are relative to center of rectangle R
  647. This calculates only the upper endpoint of the arc, but you can easily calculate the other endpoint using the same formula by calculating the absolute angle for the start point and applying the same formula.
  648. Here is a subroutine which illustrates the algorithm, in LightSpeed Pascal:
  649. { DrawCurve: draw an arc from 0 degrees until the point defined }
  650. { by 'angle'. At that point draw a 4 by 4 crosshair. }                        
  651. procedure DrawCurve (frame : Rect; angle : integer);
  652. var
  653.   x, y : integer;
  654.   xr, yr : extended;
  655.   rad : extended;
  656. begin
  657.   { Convert angle to radians }
  658.   rad := (90 - angle) / 180 * 3.14159;
  659.   { Find end point }
  660.   xr := (frame.right - frame.left) * cos(rad) / 2;
  661.   yr := (frame.bottom - frame.top) * sin(rad) / 2;
  662.   x := (frame.right + frame.left) / 2 + Num2Integer(xr);
  663.   y := (frame.bottom + frame.top) / 2 + Num2Integer(yr);
  664.   { Draw crosshair }
  665.   MoveTo(x - 4, y);
  666.   LineTo(x + 4, y);
  667.   MoveTo(x, y - 4);
  668.   LineTo(x, y + 4);
  669.   { Draw arc }
  670.   FrameArc(frame, 0, angle);
  671. end;
  672. Macintosh CopyBits no longer limited to 3K
  673. Written:    5/3/89
  674. Last reviewed:    11/21/90
  675. Inside Macintosh Volume I (page 188) says there is a 3K limit for CopyBits. Is this still true?
  676. ___
  677. The CopyBits limit is obsolete; there is no longer a 3K limit. The limit
  678. depends on the amount of RAM in your Macintosh. CopyBits tries to use the stack to do all of the copying. In most cases CopyBits is able to copy entire screen shots at one time. You might run into problems if you don’t have enough stack to hold two times the rowBytes of your source, but even in this case CopyBits will attempt to find the memory it needs.
  679. X-Ref:
  680. Inside Macintosh Volume I, page 188
  681. Why grafPort’s clipRgn should be changed before OpenPicture
  682. Written:    11/1/90
  683. Last reviewed:    12/19/90
  684. On page 189 of Inside Macintosh, Volume I, in the QuickDraw chapter’s description of OpenPicture, is the following warning:
  685. “A grafPort's clipRgn is initialized to an arbitrarily large region. You should always change the clipRgn to a smaller region before calling OpenPicture, or no drawing may occur when you call DrawPicture.”
  686. The “arbitrarily large” clipping region rectangle is set to -32767,- 32767,32767,32767 (top, left, bottom, right) for new ports. This is the largest rectangle possible. If this is not a "valid" clipping rectangle for pictures, what is? Is there some specific limit to the size of the clipping rectangle? Does it depend on either available memory or the size of the picture?
  687. ___
  688. Inside Macintosh ’s warning is based on truth but it’s incomplete. It didn’t actually say that this rectangle is invalid as a clipping region, because this is in fact a perfectly valid clipping region. But, you could run into problems if you use this as a clipping region when creating a QuickDraw picture. It’s not a matter of available memory or size; it’s a simple matter of 16-bit signed integer overflow and underflow.
  689. When you open a picture, the current clip region is recorded in the picture (this wasn’t necessarily true in some early versions of QuickDraw). When you draw the resulting picture using the picture’s picFrame as the destination rectangle, there won’t be any problems. But if you use a destination rectangle that’s larger than the picFrame, QuickDraw scales everything in the picture proportionately, including the clip region. If you allowed the default clip region to be recorded into the picture, then its rgnBBox, already as large as possible, will be made even larger. That means that the -32767 coordinates might wrap around to the positive number range, and the 32767 coordinates might wrap around to the negative number range. This leaves you with an empty clip region. Nothing at all gets drawn when the current port’s clip region is empty.
  690. If the destination rectangle is smaller than the picture’s picFrame, you won’t have any problems because the default clip region will be made smaller, and that’s no problem.
  691. This is why Inside Macintosh suggests that you make the clip region smaller than the default clip region before opening a picture. By doing this, you’re almost guaranteed that the clip region won’t get scaled to the point that it turns inside out. What size should you make it? Small enough so that the risk of the clip region’s coordinates being scaled out of QuickDraw coordinate space is minimal. I usually just set the clip region to the picFrame of the picture. It’s hard to go wrong this way.
  692. Macintosh CalcMask and CopyMask code sample
  693. Written:    2/27/92
  694. Last reviewed:    5/21/92
  695. I can’t get the black-and-white version of my lasso-type tool to work correctly with CalcMask and CopyMask. With CalcCMask it seems to work fine. What could I be doing wrong?
  696. ___
  697. CalcMask and CalcCMask are similar in that they both generate a 1-bit mask given a source bitmap. With CalcCMask, though, a pixMap can be used in place of the source bitmap; the seedRGB determines which color sets the bits in the mask image. An easy mistake to make is to forget that CalcCMask accepts a pointer to a bitmap data structure while CalcMask expects a pointer to the actual bit image. And unlike CalcCMask, which uses bounding Rects for the image’s dimensions, CalcMask uses the bitmap’s rowBytes and pixel image offsets to determine the bounding Rects for the image. A typical call to these routines would be
  698.     BitMap source, mask;
  699.     CalcMask (source.baseAddr, mask.baseAddr, source.rowBytes, 
  700.               mask.rowBytes, source.bounds.bottom-source.bounds.top, 
  701.               source.rowBytes>>1);
  702.     CalcCMask (&source, &mask, &(*source).bounds, &(*mask).bounds, 
  703.                &seedRGB, nil, 0);
  704. One last thing to note when using CalcMask is that the width of the image is in words and not bytes. To learn more about these routines, see page 24 of Inside Macintosh Volume IV and page 72 of Inside Macintosh Volume V. Also, the Developer CD Series disc contains a sample, CalcCMask&CalcMask, that shows how to use both these routines.
  705. Macintosh QuickDraw LineTo bug and workaround
  706. Written:    4/23/92
  707. Last reviewed:    7/13/92
  708. Our zooming function crashes into flames when we pass valid coordinate values to LineTo, as in the following example:
  709.     SetPort(myPort);
  710.     MoveTo(154,31619);
  711.     LineTo(74, -31742); (* You are dead! *)
  712. What can we do to avoid LineTo crashes like this?
  713. ___
  714. The QuickDraw Engineering group is aware of the problem you described. The bug probably is going to be fixed in the next release that includes bug fixes. Given that waiting for a system solution may demand more patience than is reasonable, you may want to consider including in your software some form of workaround that will prevent your users from crashing every time an operation takes the software to the limits of QuickDraw.
  715. One way to approach this problem is to replace the lineProc bottleneck. All you need to do is to check the distance between the current pen position and the line’s end, and when the distance becomes too big (let’s say more than 32000) your procedure will call StdLine a couple of times, splitting the operation in two.
  716. Replacing the bottlenecks is a very straightforward operation (which you are probably already using) and in most of the cases will only result in another level of indirection into StdLine but that will prevent your program from calling QuickDraw with parameters that are guaranteed to cause crashes.
  717. QuickDraw globals at INIT time
  718. Written:    6/1/92
  719. Last reviewed:    9/15/92
  720. If I call InitGraf before I reference CurrentA5, will CurrentA5 be valid and can the QuickDraw globals be referenced off it? The screenBits bounds values seem screwy on some machines. Does the problem lie with CurrentA5? Should I be referencing A5?
  721. ___
  722. Here’s the process used by ShowINIT, which is remarkably compatible with system software and other INITs (and it had better be, because it’s used by more than half the system extensions available):
  723. 1. It saves the value in the CurrentA5 global to restore it later.
  724. 2. It points the A5 register at 4 bytes of storage for use by the system.
  725. 3. It copies the value now in A5 into the CurrentA5 global.
  726. 4. It calls InitGraf, passing a pointer to the thePort field of a QuickDraw globals structure.
  727. 5. It opens a port and draws as necessary. [This is where all the functionality goes.]
  728. 6. After it’s done, it closes its port.
  729. 7. It copies the value saved in step (1) into the A5 register.
  730. 8. It copies the restored A5 value into the CurrentA5 global.
  731. To summarize, ShowINIT saves the A5, creates and initializes its own A5 world, does its drawing, then restores the previous A5 world. For more information on this subject, see the Macintosh Technical Note “Stand-Alone Code.”
  732. So Many Bitmaps, So Little Time
  733. Imaging    M.IM.BitMatToRegion
  734. Revised by:    Rich Collyer    December 1989
  735. Written by:    Rick Blair    April 1988
  736. This Technical Note discusses the routine BitMapToRegion, which converts a bitmap to a region, and is available in the 32-Bit QuickDraw INIT and from Apple Software Licensing.
  737. Changes since October 1989:  Added trap definitions for developers using the 32-Bit QuickDraw version of this routine without the correct MPW include file.
  738. The following routine is now available to convert a bitmap to a region:
  739. FUNCTION BitMapToRegion(region:RgnHandle; bMap:BitMap): OSErr;
  740. in C:
  741. pascal OSErr BitMapToRegion(RgnHandle region, BitMap bMap);
  742. If you are using the 32-Bit QuickDraw version of this routine without the correct MPW include file, then you need to include one of the following definitions:
  743. Pascal
  744. FUNCTION BitMapToRegion (region: RgnHandle; bMap: BitMap): OSErr;
  745.          INLINE $A8D7;
  746. C
  747. pascal OSErr BitMapToRegion (RgnHandle region, const BitMap *bMap)
  748.              = 0xA8D7;
  749. Assembly
  750. _BitMapToRegion        OPWORD        $A8D7
  751. The region will be built so that all one bits in bMap are inside the region and all zero bits are outside of it.
  752. As with all QuickDraw calls which change a region, BitMapToRegion requires you to pass an existing region (originally created by _NewRgn).  If the region cannot be built due to an insufficient heap space or a size greater than 32K, then the routine will return an appropriate error code and the region will be empty.  If the region would have exceeded 32K, the error will be rgnTooBigErr (-500).
  753. This function is useful for a number of situations where you have (or can produce) a bitmap representing an area.  You can use _CalcMask to produce such a bitmap.  Once you have a region, you can perform region operations (i.e., _PtInRgn, _UnionRgn, or _InsetRgn) or call _DragGrayRgn, for example.
  754. This call is part of the 32-Bit QuickDraw INIT ($A8D7).  If you do not wish to depend on 32-Bit QuickDraw, then you can obtain a version of BitMapToRegion in MPW object format which can be linked into an MPW program, by contacting Apple Software Licensing:
  755.             Apple Software Licensing
  756.             Apple Computer, Inc.,
  757.             20525 Mariani Avenue, M/S 38-I
  758.             Cupertino, CA, 95014
  759.             (408) 974-4667
  760.             AppleLink:  SW.LICENSE
  761. If you licensed the older version of this routine, BitMapRgn, contact Software Licensing about receiving an updated version.  We recommend you update your application to use the new version as soon as possible.
  762. The new version is now named BitMapToRegion to be consistent with the version in 32-Bit QuickDraw and the MPW interfaces.  In addition, BitMapToRegion offers new features.  You can now pass a one-bit pixelmap which has been coerced to a bitmap.  If you pass a pixelmap which is too large, then you will get a pixmapTooDeepErr (-148) error.  You can also pass the portBits of a window, much like you would do with a call to _CopyBits.
  763. There is a potential problem with this routine, since MPW 3.1 include files contain information about 32-Bit QuickDraw.  If you want BitMapToRegion to be available on all machines, then you must use the object file from Software Licensing.  The problem is that when you compile your application with MPW 3.1 or later, the 32-Bit QuickDraw version gets preference over the object file.  You must comment out the routine in the include files if you want to use the object file.  If you only care about using BitMapToRegion on machines running 32-Bit QuickDraw, then you need not do anything.
  764. A Leading Cause of Color Cursor Cursing
  765. Imaging    M.IM.ColorCursor
  766. Revised by:    Alan Mimms    October 1989
  767. Written by:    Alan Mimms    June 1989
  768. Working with color cursors you create from scratch can cause headaches.  This Technical Note may help a bit.
  769. Changes since June 1989:  Added a warning about purgeable 'clut' resources.
  770. If you’re building an application that creates color cursors, you may encounter some quirks present in Color QuickDraw that manifest themselves in hard-to-understand ways.
  771. If your cursor is, say, 15 pixels tall and 9 pixels wide, you might be tempted to use these values for the bounds.bottom and bounds.right, respectively, in your cursor’s pixel map.  Don’t.  The problem is that when the cursor’s image needs to be expanded (i.e., when you specify a two bit-per-pixel cursor and the mouse pointer is on an eight-bit screen) the _SetCCursor trap rounds the width of the pixel map in such a way that you’ll get only the space required for a 15 by 8 pixel map allocated for the expanded cursor data.  When the cursor’s image is expanded into this too-small expanded cursor data handle as a 15 by 9 pixel map, something in your heap will get munched.
  772. The cure is simple.  Make certain that you always specify that the pixmapHandle^^.bounds be 16 by 16.  This will cause _SetCCursor to properly allocate the expanded data area, and all will be well in the land.  Since the amount of data drawn for a cursor is specified by the cursor’s pixel values and 'clut' resource, trying to save a few bytes by making the bounds rectangle smaller than 16 by 16 wouldn’t have been very helpful anyway.
  773. Another potential problem is with the color cursor’s color table.  If you load the color table from a 'clut' resource using _GetCTable, you should make sure that the 'clut' is marked non-purgeable while the color cursor is in use.  If you do not take this precaution, bombs will occur if your 'clut' gets purged at in inopportune time.
  774. Color Manager Q&As
  775. Imaging    M.IM.ColorMgr.Q&As
  776. Revised by:    Developer Support Center    October 1992
  777. Written by:    Developer Support Center    October 1990
  778. This Technical Note contains a collection of Q&As relating to a specific topic—questions you’ve sent the Developer Support Center (DSC) along with answers from the DSC engineers. While DSC engineers have checked the Q&A content for accuracy, the Q&A Technical Notes don’t have the editing and organization of other Technical Notes. The Q&A function is to get new technical information and updates to you quickly, saving the polish for when the information migrates into reference manuals.
  779. Q&As are now included with Technical Notes to make access to technical updates easier for you. If you have comments or suggestions about Q&A content or distribution, please let us know by sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical questions about Q&A content to DEVSUPPORT for resolution.
  780. New Q&As and Q&As revised this month are marked with a bar in the side margin.
  781. Color Manager search and complement procedures
  782. Written:    10/7/91
  783. Last reviewed:    11/6/91
  784. The AddComp complement procedure description in Inside Macintosh Volume V, pages 145-147, is vague. The last paragraph on page V-146 states, “Complement procedures work the same as search procedures,” but SearchProc is a function, CompProc is a procedure, and each have a different number of parameters. What else does CompProc need as input and on exit?
  785. ___
  786. CompProc should be declared as a Pascal FUNCTION that returns a Boolean. The code performs a CLR.B for the return value of CompProc, so treat it like SearchProc. CompProc only uses one parameter since its one parameter is a VAR, which means it will be replaced with the correct complementary color. SearchProc returns an index in its second parameter, which is why it needs a second parameter.
  787. Using ResEdit to get Apple icon RGB values
  788. Written:    1/7/92
  789. Last reviewed:    8/1/92
  790. I am trying to find the RGB values for Apple's standard icon colors. I can’t find this information in any documentation. Is this information available?
  791. ___
  792. While the RGB values for the standard Apple icon colors (and other standard palette colors) are not explicitly documented, they are easy to obtain with ResEdit 2.1.1. In any resource file, create and open a new 'pltt' resource. Choose Load Colors from the pltt menu and pick Apple Icon Colors, and a standard palette will be created. Selecting a color will reveal its component values.
  793. ResEdit 2.1.1 is available on the latest Developer CD Series disc and from APDA.
  794. Macintosh Color Manager versus Palette Manager
  795. Written:    1/1/90
  796. Last reviewed:    8/1/92
  797. When should the Macintosh Color Manager be used and when should the Palette Manager be used?
  798. ___
  799. The Palette Manager is by far the friendlier and more versatile of the two if your application uses different colors than the default system colors. It provides all the functionality you need to customize and animate the colors in your application. You shouldn’t ever need to use the Color Manager unless you require custom color search and complement functions. When using the Palette Manager, applications will maintain their respective color environments safely as they move back and forth from foreground to background, and from one screen to another. Accomplishing this with the Color Manager calls is not worth the effort or very safe. For additional information, see the Palette Manager chapter in Inside Macintosh Volumes V and VI.
  800. Color QuickDraw Q&As
  801. Imaging    M.IM.ColorQD.Q&As
  802. Revised by:    Developer Support Center    October 1992
  803. Written by:    Developer Support Center    October 1990
  804. This Technical Note contains a collection of Q&As relating to a specific topic—questions you’ve sent the Developer Support Center (DSC) along with answers from the DSC engineers. While DSC engineers have checked the Q&A content for accuracy, the Q&A Technical Notes don’t have the editing and organization of other Technical Notes. The Q&A function is to get new technical information and updates to you quickly, saving the polish for when the information migrates into reference manuals.
  805. Q&As are now included with Technical Notes to make access to technical updates easier for you. If you have comments or suggestions about Q&A content or distribution, please let us know by sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical questions about Q&A content to DEVSUPPORT for resolution.
  806. New Q&As and Q&As revised this month are marked with a bar in the side margin.
  807. Using a Macintosh PICT file that’s larger than available memory
  808. Written:    6/18/90
  809. Last reviewed:    9;/24/91
  810. How can I read a 2 MB PICT file into only 1 MB of memory?
  811. ___
  812. You can’t read it in since you don’t have enough memory, but drawing the picture contained in the file using a technique called “spooling” increases your chances of using a 2 MB PICT file with 1 MB memory. Spooling is documented in the Color QuickDraw chapter of Inside Macintosh Volume V (pages 88-89).
  813. Getting a single scan line from a PICT file
  814. Written:    6/18/90
  815. Last reviewed:    9/24/91
  816. Is there any way to obtain a particular scan line from a PICT file?
  817. ___
  818. A PICT file may contain more than just pixmaps, so getting one scan line out of it is not possible. The file may also contain other elements that overlap, such as rects and arcs. The only way to obtain a single line is to draw it offscreen and then, once the whole image is in memory, you can go and study individual pixels.
  819. Determining pixel depth from PICT files
  820. Written:    6/20/90
  821. Last reviewed:    9/17/91
  822. How do you find out the pixel size of a PICT file on the disk?
  823. ___
  824. A picture is by nature independent of depth. For example, you can have a picture containing DrawRects and LineTos and therefore lacking of any info regarding depth.
  825. On the other hand, if the picture you are looking at has pixmap opcodes in it, then each pixmap contains its own pixel size and in this case a picture can have a number of depths associated with it.
  826. If you want to see the pixel size for each pixmap opcode in a picture, replace all the bottleneck routines and every time the bitsProc is called you can see the pixmap and get the info out. Since the picture is in a file, you can use the spooling technique described in the QuickDraw chapter in Inside Macintosh Volume V. Be ready to deal with multiple, possibly different, pixmaps as well as direct pixmaps if the picture was created under 32-bit QuickDraw.
  827. ”KnowsPICT,” on the Developer CD Series disc, extracts this kind of information. The System 7.0 Picture Utilities package gets this information too.
  828. Direct RGB PICT file compression
  829. Written:    10/24/90
  830. Last reviewed:    2/14/91
  831. How are bits packed in direct RGB PICT files created by 32-Bit QuickDraw? I looked at the Macintosh Technical Note “Things You Wanted To Know about _PackBits…”, but this run-length encoded compression is clearly inefficient for cases where pixelSize is greater than 8 bits. I write software for machines other than Macintosh that decodes PICT files; therefore, I cannot issue any QuickDraw calls such as _unpackBits.
  832. ___
  833. You’re quite right; compressing direct pixels using straight run-length encoding doesn’t work very well. Fortunately, direct pixel maps aren’t compressed this way. Compression schemes are discussed in Inside Macintosh Volume VI in the section titled “The New OpCodes: Expanded Format.”
  834. In short, if the packType field holds the value 1, then no compression is done at all. The complete pixel image is saved in the PICT. If the packType field holds the value 2 and the pixel map is 32-bits per pixel, then all that’s done is that the alpha-channel byte is removed. So this:
  835.                        00 FF FF FF  00 FF FF FF
  836. is compressed to:
  837.                        FF FF FF  FF FF FF
  838. If the packType field holds the value 3 and the pixel map is 16 bits per pixel, then run-length encoding is done, but not through PackBits. Instead, a run-length encoding algorithm private to QuickDraw is used. This algorithm is very similar to PackBits, but where PackBits compresses runs of bytes, this routine compresses runs of words. The format of the resulting data is exactly the same as described in the Technical Note “Things You Wanted To Know about _PackBits…”, but you’ll get words instead. To build on the example in this Tech Note, lets say the 16-bit pixel image begins with these pixel values:
  839.     AAAA AAAA AAAA 8080 0000 2A2A AAAA AAAA AAAA AAAA 8080 0000
  840.     2A2A 2222 AAAA AAAA AAAA AAAA AAAA AAAA AAAA AAAA AAAA AAAA
  841. After being packed by QuickDraw’s internal compression routine, this becomes:
  842.     FE AAAA
  843.     02 8080 0000 2A2A
  844.     FD AAAA
  845.     03 8080 0000 2A2A 2222
  846.     F7 AAAA
  847. or
  848.     FEAA AA02 8080 0000 2A2A FDAA AA03 8080 0000 2A2A 2222 F7AA AA
  849.     *      *                 *      *                      *
  850. where the asterisks mark the flag-counter bytes. Notice that you can’t assume that the pixel values are word-aligned. PackBits packs data 127 bytes at a time, though it will do this for up to 32,767 total bytes. Similarly, the internal compression routine packs data 127 words at a time.
  851. If the packType field holds the value 4 and the pixel map is 32-bits per pixel, then run-length encoding via PackBits is done, but only after some preprocessing is done. QuickDraw first rearranges the color components of the pixels so that each color component of every pixel is consecutive. So the following four pixels (the row below the pixel values indicates a = alpha channel, r = red, g = green, b = blue, and the pixel offset):
  852.             00 FF FF FF  00 FF C0 00  00 FF 80 00  00 C0 80 00
  853.             a0 r0 g0 b0  a1 r1 g1 b1  a2 r2 g2 b2  a3 r3 g3 b3
  854. is rearranged to become:
  855.             FF FF FF C0  FF C0 80 80  FF 00 00 00
  856.             r0 r1 r2 r3  g0 g1 g2 g3  b0 b1 b2 b3
  857. The first four bytes are the red components of the four pixels, the next four bytes indicate the green components of the four pixels, and so on. The alpha channel isn’t included unless the cmpCount field contains 4 rather than the normal 3. If cmpCount contains 4, then all the alpha channel bytes are placed before the red bytes. Once this is done, then PackBits is called to compress the rearranged data.
  858. Those are the only four compression schemes (including no compression) that are supported for direct pixel maps in PICTs. As always, reading PICTs yourself puts you in danger of not being able to read PICTs generated by future versions of QuickDraw. For compatibility reasons, these compression algorithms as I’ve described them probably can’t change in the future. It’s possible that new values for packType could be implemented though.
  859. X-Ref:
  860. Macintosh Technical Note “Things You Wanted To Know about _PackBits…”
  861. Saving 32-bit Macintosh PICTs
  862. Written:    10/30/90
  863. Last reviewed:    2/20/91
  864. I am using a packType=4 and have several questions about saving Macintosh 32- bit images in a PICT format:
  865. (1) What are the ramifications of using cmpCount=3 as opposed to cmpCount=4?
  866. (2) How is the pixData actually stored? According to several references, each line is run-length encoded; that is, [byteCount][data]. If rowBytes>250 then byteCount is a word. After looking at several examples, I came to the conclusion that you are actually using packBits and that the term “run-length” encoded is a misnomer.
  867. ___
  868. (1) The difference between using cmpCount=3 or cmpCount=4 is that in the first case only the R, G and B values are stored in the picture; in the second case QuickDraw stores in the picture the alpha channel plus R, G and B. cmpCount=4 can be used when it is important to also save the alpha channel (as when you have some flags stored there).
  869. (2) Unless rowBytes is less than 8, the PixMap is compressed using PackBits, and the length is a word or a byte depending on rowBytes, but it always refers to the number of bytes comprising one scan line. My guess is that “run-length encoding” refers to the fact that pictures have data organized one row at a time.
  870. To show how direct RGB PixMaps are stored inside a picture, I am including the decoding of a picture that I created to show how the different packing schemes change the resulting PixMap opcode data. First I created a direct RGB PixMap and drew three lines into it. The first line is 8 pixels long with a color of {0x1111,0xAAAA, 0x7777}, the third line is 8 pixels of {0xFFFF, 0x3333, 0xBBBB} and the line in between is two pixels of the first color then two pixels of the second color and so on until you make 8 pixels. Then I created a picture made of CopyBits calls copying the same lines but using different packing schemes. Finally I dumped the contents and the result is what you see here. I have put comments I think help make it clear how the packing scheme of choice changes the results.
  871. I recommend that you have the Inside Macintosh Volume V QuickDraw chapter at hand to check the opcodes and data associated with them. If you had Inside Macintosh Volume VI then you wouldn't need to also check the 32-Bit QuickDraw docs for the direct RGB PixMap opcodes. The Technical Note “Things You Wanted To Know about _PackBits…” gives details on how the packed data is arranged.
  872. 0256 0000 0000 0008 0008                   /* size and rect        */
  873. 0011 02FF 0C00 FFFF FFFF                   /* PICT2 Header         */
  874. 0000 0000 0000 0000 0008
  875. 0000 0008 0000 0000 0000
  876. 001E                                       /* Default hilite       */
  877. 001A FFFF 3333 BBBB                        /* RGB Fore Color       */
  878. 0001 000A 8001 8001 7FFF 7FFF              /* ClipRgn              */
  879. 009A              /* direct pixels opcode; see IM VI QD chapter for details */
  880. 0000 00FF 8020 0000 0000 0003 0008 0000    /* See IM V or VI QuickDraw chapter
  881. */
  882. 0001 0000 0000 0048 0000 0048 0000 0010    /* packType 0001 = no packing */
  883. 0020 0003 0008 0000 0000 006D A7DC 0000
  884. 0000 0000 0000 0003 0008 0000 0000 0003
  885. 0008 0000
  886. 0011 AA77 0011 AA77 0011 AA77 0011 AA77    /* line one xRGB after xRGB */
  887. 0011 AA77 0011 AA77 0011 AA77 0011 AA77
  888. 0011 AA77 0011 AA77 00FF 33BB 00FF 33BB    /* second line same */
  889. 0011 AA77 0011 AA77 00FF 33BB 00FF 33BB
  890. 00FF 33BB 00FF 33BB 00FF 33BB 00FF 33BB    /* third line same  */
  891. 00FF 33BB 00FF 33BB 00FF 33BB 00FF 33BB
  892. 009A                                       /* same direct pixels opcode   */
  893. 0000 00FF 8020 0000 0000 0003 0008 0000
  894. 0002 0000 0000 0048 0000 0048 0000 0010    /* packType 2 = fourth byte off*/
  895. 0020 0003 0008 0000 0000 006D A7DC 0000
  896. 0000 0000 0000 0003 0008 0003 0000 0006
  897. 0008 0000
  898. 11AA 7711 AA77 11AA 7711 AA77              /* one line of RGB after RGB   */
  899. 11AA 7711 AA77 11AA 7711 AA77              /* compare with previous       */
  900. 11AA 7711 AA77 FF33 BBFF 33BB              /* same here*/
  901. 11AA 7711 AA77 FF33 BBFF 33BB
  902. FF33 BBFF 33BB FF33 BBFF 33BB              /* and here */
  903. FF33 BBFF 33BB FF33 BBFF 33BB
  904. 009A                                       /* bits opcode */
  905. 0000 00FF 8020 0000 0000 0003 0008 0000
  906. 0004 0000 0000 0048 0000 0048 0000 0010    /* packType 4 = pack     */
  907. 0020 0003 0008 0000 0000 006D A7DC 0000    /* componentCount = 3    */
  908. 0000 0000 0000 0003 0008 0006 0000 0009    /* R,G and B separated   */
  909. 0008 0000
  910.                     /* for details on packed data see Tech Note referenced above*/
  911. 06                  /* first line made of 6 bytes including count    */
  912. F9 11F9 AAF9 77     /* -(-7)+1 of 11, -(-7)+1 of AA, and
  913.                                    -(-7)+1 of 77 -> 8 RGB triplets   */
  914. 19                                   /* second row made of $19 bytes */
  915. 1711 11FF FF11 11FF FFAA AA33 33AA AA33 3377 77BB BB77 77BB BB
  916.                                            /* $17+1 unpacked values */
  917. 06                                         /* third line same as first      */
  918. F9FF F933 F9BB                             /* repeated R and B and G values */
  919. 009A                                          /* bits opcode again */
  920. 0000 00FF 8020 0000 0000 0003 0008 0000
  921. 0004 0000 0000 0048 0000 0048 0000 0010       /* same packing = 4 but       */
  922. 0020 0004 0008 0000 0000 006D A7DC 0000       /* component count = 4        */
  923. 0000 0000 0000 0003 0008 0009 0000 000C       /* alpha channel, R, G, and B */
  924. 0008 0000
  925. 08                                            /* first line */
  926. F9 00F9 11F9 AAF9 77
  927.                 /* same as before but packing the high byte (00 value) also */
  928. 1B    /* second line first has -(-7)+1 '00' and then the same line as above */
  929. F900 1711 11FF FF11 11FF FFAA AA33 33AA AA33 3377 77BB BB77 77BB BB
  930. 08                                            /* third line same as first */
  931. F900 F9FF F933 F9BB
  932. 00FF                                          /* end of PICT */
  933. A section of the code that produces this picture follows:
  934.     RGBColor    oneColor = {0x1111, 0xaaaa, 0x7777},
  935.                 twoColor = {0xffff,0x3333,0xbbbb};
  936.     SetGWorld(GgwPtr, nil);                   /* set the offscreen GWorld */
  937.     if ( LockPixels(GgwPtr -> portPixMap) )
  938.     {
  939.         EraseRect(&(GgwPtr->portRect));
  940.         RGBForeColor(&oneColor);
  941.         MoveTo(0,0);
  942.         LineTo(7,0);
  943.         MoveTo(0,1);
  944.         LineTo(1,1);
  945.         RGBForeColor(&twoColor);
  946.         MoveTo(2,1);
  947.         LineTo(3,1);
  948.         RGBForeColor(&oneColor);
  949.         MoveTo(4,1);
  950.         LineTo(5,1);
  951.         RGBForeColor(&twoColor);
  952.         MoveTo(6,1);
  953.         LineTo(7,1);
  954.         MoveTo(0,2);
  955.         LineTo(7,2);
  956.         SetRect(&localR,0,0,8,3);
  957.         rr = localR;
  958.         p = OpenPicture(&(GgwPtr->portRect));
  959.         /* first no packing */
  960.         (*(GgwPtr -> portPixMap)) -> packType = 1;
  961.             CopyBits((*(GgwPtr -> portPixMap)),(*(GgwPtr -> portPixMap)),
  962.                 &rr,&localR,srcCopy,nil);
  963.         /* second pack 2: remove alpha chanel */
  964.             OffsetRect(&localR,0,3);
  965.         (*(GgwPtr -> portPixMap)) -> packType = 2;
  966.             CopyBits((*(GgwPtr -> portPixMap)),(*(GgwPtr -> portPixMap)),
  967.                 &rr,&localR,srcCopy,nil);
  968.         /* third pack 4: packing component by component */
  969.             OffsetRect(&localR,0,3);
  970.         (*(GgwPtr -> portPixMap)) -> packType = 4;
  971.             CopyBits((*(GgwPtr -> portPixMap)),(*(GgwPtr -> portPixMap)),
  972.                 &rr,&localR,srcCopy,nil);
  973.         /* The last case is pack 4 but storing the alpha channel also */
  974.             OffsetRect(&localR,0,3);
  975.         (*(GgwPtr -> portPixMap)) -> packType = 4;
  976.         (*(GgwPtr -> portPixMap)) -> cmpCount = 4;
  977.             CopyBits((*(GgwPtr -> portPixMap)),(*(GgwPtr -> portPixMap)),
  978.                 &rr,&localR,srcCopy,nil);
  979.         ClosePicture();
  980.     UnlockPixels(GgwPtr -> portPixMap);
  981.     }
  982. X-Ref:
  983. “Color QuickDraw,” Inside Macintosh Volume V
  984. “Color QuickDraw,” Inside Macintosh Volume VI
  985. Macintosh Technical Note “Things You Wanted To Know about _PackBits…”
  986. BitMapToRgn for nonColor QuickDraw Macintosh models
  987. Written:    11/9/90
  988. Last reviewed:    2/20/91
  989. Is _BitmapToRegion available on any pre-System7 nonColor QuickDraw configurations such as the Macintosh Classic, Plus, or SE? If not, is source or a library module available so that I don't have to take the time and compatibility risk of rolling my own?
  990. ___
  991. BitMapToRegion works on pre-color Macintosh systems. You can license BitMapToRegion from
  992.     Software Licensing
  993.     Apple Computer, Inc.
  994.     20525 Mariani Ave. MS:38-I
  995.     Cupertino, CA  95014
  996.     AppleLink: SW.LICENSE
  997.     Phone:(408) 974-4667
  998. Macintosh QuickDraw pixel map stack requirements
  999. Written:    12/3/90
  1000. Last reviewed:    5/21/91
  1001. What are the guidelines for determining how much of an image CopyBits can copy to a Macintosh pixel map at one time, given a particular set of characteristics for the source map and the destination map and given how much stack space is available? For example, say that we have an 8-bit-deep pixMap to be copied to a 32-bit-deep pixMap using the ditherCopy mode and expanded by
  1002. a factor of 4, and we have 45K of stack space.
  1003. ___
  1004. CopyBits’ stack requirement depends on the width of each scan line (rowBytes). The rule of thumb is that you need at least as much stack as the rowBytes value in your image (which can be huge with 32-Bit QuickDraw), with the following additional modifiers: add an additional rowBytes for dithering; add an additional rowBytes for any stretching (source rect != dest rect); add an additional rowBytes for any color map changing; add an additional rowBytes for any color aliasing. The stack space you need is roughly five times the rowBytes of your image. In general, you’re better off processing narrower scan lines. Reducing the vertical size will not affect stack requirements. Narrow, tall bands (if you can use them) will reduce the stack requirements.
  1005. Color and nonColor QuickDraw trap dispatch differences
  1006. Written:    1/28/91
  1007. Last reviewed:    2/13/91
  1008. Why does a call to RGBForeColor cause a corruption of the stack without resulting in an unimplemented trap error on nonColor QuickDraw Macintosh systems?
  1009. ___
  1010. The trap dispatcher on Color QuickDraw and nonColor QuickDraw machines are different. If you look at page 89 of Inside Macintosh Volume I, you’ll see the toolbox trap word format as it was in the days before Color QuickDraw. Bit 9 was “reserved for future use” and was ignored by the trap dispatcher, and so it was normally set to 0. That means that valid toolbox traps could either look like $A8XX or $A9XX as long as the auto-pop bit was turned off. Color QuickDraw machines have a trap dispatcher that uses that reserved bit to allow for more trap words, and therefore it has a much larger trap dispatch table. Color QuickDraw traps have that reserved bit set, so those traps look like $AAXX or $ABXX.
  1011. When a nonColor QuickDraw machine tests to see if a trap is implemented or not, it just checks the trap dispatch table to see if a routine is implemented for that trap or not. Because the reserved bit is ignored, trap words that look like $AAXX are treated as equivalent to $A8XX and trap words that look like $ABXX are treated as equivalent to $A9XX. The trap word for RGBForeColor is $AA14. If you call RGBForeColor on a nonColor QuickDraw machine, $AA14 is treated as $A814, which is the trap word for SetFractEnable. SetFractEnable is implemented on 128K ROM machines or greater, so no unimplemented trap error occurs.
  1012. If you look at recent DTS sample programs, such as the Utilities sample (SC.025.Utilities, which you can find on AppleLink in Developer Support and on the current developer CD), you’ll see a routine in Utilities.c called TrapExists. It takes into account the size of the trap dispatch table so that you can tell in one call whether a routine is implemented or not regardless of whether it’s a Color QuickDraw trap or not and regardless of what kind of Macintosh you’re running on.
  1013. Under system software version 7.0, the trap dispatcher is modified on nonColor QuickDraw machines so that many Color QuickDraw traps are implemented and work as well as they can in black and white.
  1014. Macintosh OpenCPicture 72 dpi calculation bug
  1015. Written:    2/12/91
  1016. Last reviewed:    2/20/91
  1017. The 32-Bit QuickDraw _OpenCPicture call incorrectly calculates the 72 dpi frame width if the height of the native resolution srcRect exceeds 910 dots. To work around this problem, I calculate the 72 dpi frame independently, and store it in the PicHandle returned by _OpenCPicture.
  1018. ___
  1019. It’s a known bug that under Macintosh Systems 6.0.5 and 6.0.7 with 32-Bit QuickDraw 1.2, OpenCPicture doesn’t properly calculate the right coordinate of the 72 dpi picFrame if the height of the srcRect (native resolution rectangle) multiplied by 72 exceeds $0000FFFF. That works out to a maximum height of 910 pixels, just as you found. This bug is fixed in System 7.0, but gestaltQuickDrawVersion returns $0220 both under Systems 6.0.5 and 7.0, so you can’t tell whether the bug is fixed that way. Instead, you should use Gestalt with the gestaltSystemVersion selector. If the returned value is $0700 or greater, then let OpenCPicture handle the picFrame calculation; otherwise you should do the calculation yourself.
  1020. GetGWorldPixMap bug and workaround
  1021. Written:    3/12/91
  1022. Last reviewed:    10/9/91
  1023. Why does GetGWorldPixMap (when called on a Macintosh II, IIcx, or IIx running system software version 6.0.5 or 6.0.7 with 32-Bit QuickDraw 1.2) return a combination of the device field (two bytes) and the first two bytes of the portPixMap field? Is this a bug?
  1024. ___
  1025. Your analysis of GetGWorldPixMap is exactly right: It doesn’t work correctly in system software version 6.0.5 and 6.0.7 with 32-Bit QuickDraw 1.2. It returns a value that’s two bytes before the value it’s supposed to return.
  1026. The solution is to use GWorldPtr->portPixMap instead of GetGWorldPixMap. It’s safe to do this, but you should use GetGWorldPixMap under System 7. Not only is the bug fixed there, but dereferencing the port is dangerous under System 7 because it may not be CGrafPort. Use Gestalt with the gestaltQuickdrawVersion selector to determine whether you can use GetGWorldPixMap. If Gestalt returns a value from gestalt8BitQD ($0100) through gestalt32BitQD12 ($0220), then GetGWorldPixMap either doesn’t exist or is the buggy version. If it returns gestalt32BitQD13 ($0230) or higher, then GetGWorldPixMap does exist and works correctly. Interestingly, GetGWorldPixMap can be called on a black-and-white QuickDraw machine under System 7. It returns a handle to a structure which should be treated as a BitMap structure, though there are some undocumented fields after the normal BitMap fields. To tell whether GetGWorldPixMap is available on a black-and-white QuickDraw machine, you must check the system software version by calling Gestalt with the gestaltSystemVersion selector. Ifit returns $0700 or higher, GetGWorldPixMap is available.
  1027. System 7 TextMode problem and workaround
  1028. Written:    6/12/91
  1029. Last reviewed:    8/13/91
  1030. Our application uses the TextMode (blend + mask) as documented in Inside Macintosh Volume V (blend is equal to the current ditherCopy constant) to make translucent text. Under System 7, this transfer mode causes garbage to appear when the text is drawn. Is there a way to work around the problem? Will there be a fix?
  1031. ___
  1032. The problem you are seeing is due to the use of CopyDeepMask instead of the old-fashioned CopyBits to do the job. It is being studied now, and the hope is that it will work as advertised in a future release. One workaround is to render the text to an off-screen pixmap and then call CopyBits (using blendMode) to actually put it in the picture.
  1033. Using dithering and animation on the same Macintosh image
  1034. Written:    6/19/91
  1035. Last reviewed:    10/15/91
  1036. When setting up a dithered grayscale image for subsequent animation (to adjust brightness, for example), a conflict arises between the use of Palette animation and the ditherCopy CopyBits mode.This problem is demonstrated in the develop #5 GiMeDaPalette code sample: If you change srcCopy to ditherCopy in the CopyBits call, then run the program and selected Animate, the resulting image is pure black and white, with what appears to be an attempt to dither with just the black and white color table entries (that are not reserved for animation).
  1037. This happens because ditherCopy tries to use the inverse table to do color matching, but when the image is animated, the inverse table colors are limited to just black and white.
  1038. To work around the problem, you can jump into the bottlenecks and when you see the PICT hitting the opcode for CopyBits, change the PICT from a srcCopy to a ditherCopy. This way the dithering happens when you do the call to DrawPicture and not later on. This makes it possible to use dithering and animation on the same image.
  1039. Rendering color PICTs in a black-and-white environment
  1040. Written:    7/22/91
  1041. Last reviewed:    9/17/91
  1042. I want to be able to render a color PICT as a black-and-white image substituting patterns for colors. My images are pretty small and have under 16 colors. What do you suggest as the easiest way?
  1043. ___
  1044. One easy way is to take advantage of 32-Bit QuickDraw and System 7.0’s ditherCopy transfer mode modifier or flag (documented in Inside Macintosh Volume VI, page 17-17). Call DrawPicture into an offscreen pixmap with the pixel depth of the original color PICT. Then call CopyBits to copy the pixmap to the screen, with srcCopy + ditherCopy as the transfer mode. This will result in a nicely dithered image on the black-and-white end.
  1045. Under System 6 without 32-Bit QuickDraw, the solution is not nearly so cut and dried. One way might be to take advantage of the fact that DrawPicture goes through the QuickDraw bottlenecks for drawing. For each grafproc in your PICT, you'd intercept StdBits during DrawPicture and call your own dithering routine to examine the foreground color and set the pen pattern or fill pattern so that it has about the same lightness as the original color.
  1046. Well, this came out as a great sales pitch for writing a System 7-savvy app!
  1047. Highlighting ignored if foreground same as background color
  1048. Written:    8/7/91
  1049. Last reviewed:    9/24/91
  1050. Under System 7, but not System 6, HiliteColor is not used for InvertRect when the hilite bit is set and the background is exactly black (R=G=B=$0000). Also, HiliteColor doesn’t draw when a pen mode of XOR is used in a LineTo call.
  1051. ___
  1052. The problem you encounter exists whenever the background and foreground color are the same when using highlight mode. If the foreground color is the same as the background color, highlighting is ignored. Therefore, when you set the foreground color to white, you should set the background color to something other than the default color of white.
  1053. Gestalt 'qdrw' selector bug and workaround
  1054. Written:    8/1/91
  1055. Last reviewed:    10/9/91
  1056. Why does Gestalt tell me I have Color QuickDraw features on a non-Color QuickDraw machine?
  1057. ___
  1058. The gestaltQuickdrawFeatures ('qdrw') selector, used for determining your system’s Color QuickDraw features, has a bug that causes it to tell you incorrectly that noncolor machines have color. The fix is quite simple: Gestalt has another selector, gestaltQuickdrawVersion ('qd  '), which simply returns the QuickDraw version number. This version number is < gestalt8BitQD for classic QuickDraw and >= gestalt8BitQD for Color QuickDraw (see Inside Macintosh Volume VI, page 3-39, for more information). The trick is to ask Gestalt for the QuickDraw version first; once you’ve determined that you have Color QuickDraw, the 'qdrw' selector is OK to use to find out specifics.
  1059. Version 2 PICTs on pre-Color QuickDraw models
  1060. Written:    8/13/91
  1061. Last reviewed:    10/22/91
  1062. Inside Macintosh Volume V says a System 4.1 (and later) patch ensures that version 2 PICTs are displayed correctly on earlier machines that don’t have Color QuickDraw, such as the Macintosh Plus and SE. However, my version 2 PICT, consisting primarily of a PixMap (opcode = $90 since rowbytes <8) displays correctly on a Macintosh IIfx but displays garbage on a Macintosh SE.
  1063. ___
  1064. The PICT problem you reported is caused by a bug in 6.0.7 QuickDraw. The workaround for the time being is to:
  1065. • Use System 7.0, where it’s been fixed, or
  1066. • Don’t use opcode $90. Instead, use padding so that opcode $98 can be used. (Opcode $98 is the packed copybits version that works for rowbytes >= 8.). You can do this by creating the picture with a PixMap that’s wider than you actually need, and then use the clip region to clip out the part you don’t need.
  1067. GetPixelsState is slow sometimes
  1068. Written:    8/27/91
  1069. Last reviewed:    9/24/91
  1070. Why do I sometimes see incredible slowdowns under System 7.0 when calling either GetPixelsState or LockPixels (I’m not sure which) for the PixMapHandle of a GWorld allocated in temporary memory?
  1071. ___
  1072. GetPixelsState takes an arbitrary amount of time since it makes a call to RecoverHandle to get the handle pointing to the baseaddr. Therefore, the slowdown you see as actually due to the call to RecoverHandle, which is slow because it must traverse the heap to find the pointer to the baseaddr. LockPixels is not responsible for the slowdown because it does not make call to any traps which could take an extended amount of time.
  1073. OpenCPicture and PICTs other than 72 dpi
  1074. Written:    10/2/91
  1075. Last reviewed:    10/8/91
  1076. Can I use OpenCPicture to create PICTs with a higher resolution than 72 dots per inch (dpi)?
  1077. __
  1078. There’s good news and bad news: The good news is that you’re on top of the situation, which means the bad news is that there aren’t better ways to do what you want to do, mostly. Here’s the scoop:
  1079. You can use vRes and hRes in pictures opened with OpenCPicture to tell QuickDraw it’s not a 72-dpi picture, and as long as the application that receives the picture uses DrawPicture to image it, QuickDraw will Do The Right Thing—scaling it on the screen to 72 dpi instead of making it humongously large. Unfortunately, this way you lose hairlines; if you print such a picture to a 72 dpi grafPort (like the LaserWriter driver normally returns), you’ll get 1/72-inch lines instead of 1/300-inch lines as you probably want.
  1080. (This _can_ work correctly, but the receiving application has to notice your picture is bigger than 72 dpi and ask PrGeneral to increase the resolution of the printing grafPort accordingly, and this doesn’t always or often happen.)
  1081. No System 7 QuickDraw alpha channel support
  1082. Written:    10/23/91
  1083. Last reviewed:    11/27/91
  1084. How can I directly access the alpha channel (the unused 8 bits in a 32-bit direct pixel using QuickDraw) under System 7? Under System 6 it was easy, but under System 7’s CopyBits() the alpha channel works with srcXor but not with srcCopy.
  1085. ___
  1086. With the System 7.0 QuickDraw rewrite, all “accidental” support for the unused byte was removed, because QuickDraw is not supposed to operate on the unused byte of each pixel. QuickDraw has never officially supported use of the extra byte for such purposes as an alpha channel. As stated in Inside Macintosh Volume VI, page 17-5, “8 bits in the pixel are not part of any component. These bits are unused: Color QuickDraw sets them to 0 in any image it creates. If presented with a 32-bit image—for example, in the Copybits procedure—it passes whatever bits are there.”
  1087. Therefore, you cannot rely on any QuickDraw procedure to preserve the contents of the unused byte, which in your case is the alpha channel. In fact, even CopyBits may alter the byte if stretching or dithering is involved in the copybits by setting them to zero. Therefore, the only possible workarounds for this problem are to not use the unused byte for alpha channel storage since the integrity of the data cannot be guaranteed; or, to not use QuickDraw drawing routines which can alter the unused byte.
  1088. BitsToRgn and MPW BitMapToRegionGlue
  1089. Written:    10/29/91
  1090. Last reviewed:    12/11/91
  1091. Which version of the system software first contained the call BitsToRgn? Is there a workaround for this call if my users have an earlier version of system software?
  1092. ___
  1093. The call BitmapToRegion was introduced with 32-bit QuickDraw and became fully documented in Volume VI of Inside Macintosh, which is primarily System 7 information. However, since the differences between System 7’s QuickDraw and 32-bit QuickDraw are minor, most of System 7’s QuickDraw routines are available in system software prior to System 7.0 using the 32-bit QuickDraw Init.
  1094. To check to see if a system contains 32-bit QuickDraw, you can use the following snippet of code:
  1095.     /* Find out if GWorlds and CQD are implemented on this machine */
  1096.     (void) Gestalt (gestaltQuickdrawVersion, /*<*/&qdVersion);
  1097.     gHasGWorlds = (qdVersion > gestaltOriginalQD && 
  1098.                    qdVersion < gestalt8BitQD)
  1099.                   || qdVersion >= gestalt32BitQD;
  1100. If you are using MPW as a development platform, MPW has a library call you can use that will allow you to use the routine regardless of whether or not 32-bit QuickDraw exists. The glue routine is called BitMapToRegionGlue() and is available to MPW users. Substitute this call for BitMapToRegion calls and the glue code will take care of patching in the proper code if 32-bit QuickDraw does not exist. If you’re using Think C, you can use the oConv utility to convert the MPW object file into a Think C usable format.
  1101. Ensuring even rowBytes for 'cicn' resources
  1102. Written:    12/4/91
  1103. Last reviewed:    1/27/92
  1104. Is there any way to force bitmaps and masks within a 'cicn' resource to have an even rowBytes (using ResEdit)? I want to avoid duplicating icon bitmaps—one for color systems set to B&W and one for B&W systems—to reduce program size as well as development and maintenance costs. The bitmaps in the 'cicn' can also be sized specifically to the task, whereas the old B&W icons are of a fixed size and contain no sizing information. It’s simple enough to read in a 'cicn' and extract the bitmap. The problem is that on a 68000 (no Color QuickDraw), if rowBytes is odd, an odd address trap results.
  1105. ___
  1106. There isn’t any way to get ResEdit itself to create BitMaps with even rowBytes for 8 x 8 'cicn' resources, but here are few suggestions:
  1107. You could process your 'cicn' resources first, so that they have BitMaps as you require them. To alter the resource with a quick little program would be trivial, especially given that the bitmap data sits last in the 'cicn'. All you’d need to do is expand the bitmap image data by padding each line to an even length and then changing the rowBytes value. Or you could de-rez the 'cicn's and patch them with a text editor, either by hand or with a search-and-replace script of some kind.
  1108. CopyBits blend mode: OpColor's affect & eliminating banding
  1109. Written:    12/11/91
  1110. Last reviewed:    2/17/92
  1111. I have two grey-colored pixmaps that I wish to blend together; one is on the screen, the other in an offscreen pixmap. I use CopyBits to copy the offscreen to the screen, but it does not seem to blend them. Instead, it seems to match the colors of the screen bitmap to the closest colors in some table, thus having the effect of reducing the number of colors displayed on the screen bit map. Any suggestions?
  1112. ___
  1113. There are two distinct questions here: 1) Why ain’t it blending? and 2) What’s this banding for? The first problem is almost certainly because OpColor isn’t set properly. This is a third, implicit, operand on several arithmetic graphics operations, including blend. For blend, it describes the proportions to mix the source and destination colors in the blend. For an equal mix, you should set this color to a halfway gray. (Call OpColor() with a color where red, green, and blue all equal $8000.) This effect is described in the description of the blend mode on page 60 of Inside Macintosh, Volume V. Unfortunately, the initial value for OpColor is black (0,0,0), so you were seeing no mixing of your offscreen data.
  1114. The second half of your question is why you’re getting a banding effect. (When you fix the above problem, you’ll still get banding.) Unfortunately, the arithmetic modes are constrained by the size of the inverse table. As your screen no doubt uses the default 4-bit inverse table, you’ll find that you’ll get only 2^4 = 16 levels of gray. If you enlarge your screen’s inverse table to 5 bits, the maximum allowable, you’ll still only get 32 gray levels. (To do this, set the gdResPref field in the GDevice to 5, then call MakeITable().) The only way to get a fully-gradual, great-looking effect is to do all the work offscreen in 24-bit deep pixmaps, and then copy it to the screen. Because they can operate directly on colors, rather than having to work through the intermediary of color indices, direct pixmaps are not limited by inverse tables (in fact, they don’t even have real inverse tables). You could use 16-bit pixmaps, but they only provide 32 grays (having only 5 bits for each component), so this wouldn’t be any better than increasing the size of the inverse table.
  1115. Icon dimming under System 7 and System 6
  1116. Written:    1/6/92
  1117. Last reviewed:    2/6/92
  1118. When you bring up the Control Panels window under System 7 on a color system and click on a control panel item icon, it paints itself that fancy gray. How can I get that effect?
  1119. ___
  1120. To get the fancy System 7 icon dimming to work in your program, use the icon drawing routines PlotIconID or PlotCIconHandle with an IconTransformType of ttSelected. Both of these routines and their tranform types are used by the Control Panel and are described in the Macintosh Technical Note “Drawing Icons the System 7 Way.”
  1121. If you want the same effect under System 6, you’ll have to emulate the dimming of the icons via QuickDraw, by installing a color search proc to dim the RGB values that the icon uses.  On page 146 of Inside Mac volume V is a description of how to define and install your custom search proc.
  1122. QuickDraw out of memory if debugger invoked by “Jackson”
  1123. Written:    3/11/92
  1124. Last reviewed:    4/7/92
  1125. I am getting a strange bug in which the Macintosh debugger is being invoked by an A-trap marked “Jackson” when I call SetCCursor in certain situations and a second monitor is hooked up. The cursor structure being passed appears to be valid. I’ve also been crashing unexpectedly in this same spot for the past few weeks. I assume Jackson is some kind of error assertion that was left in System 7’s Color QuickDraw code. What gives?
  1126. ___
  1127. Jackson was a code name for 32-Bit QuickDraw. The trap you refer to is in fact never called; it’s not supposed to be encountered by you ever. The trap is reserved for Apple to use in future versions of Color QuickDraw. If you examine the code directly preceding the _Debugger, you will notice that it is doing
  1128.         MOVEQ      #$19,D0
  1129.         JSR        ([$1524])
  1130. which for you and me is
  1131.          MoveQ #25,D0                ; say that memory is full…
  1132.         _SysError                    ; and call syserror
  1133. the line following would be...
  1134.         _Debugger ; Hey! sysError came back! Better drop into the debugger
  1135. What’s all this tell you? You have a debugger installed that is rts’ing from the SysError vector (you aren’t supposed to return from SysError normally), or you have installed your own SysError vector which is rts’ing. At any rate, if you examine the code directly following the debugger statement and see what it does, you might imagine the source code looks something like this:
  1136. MemFull       MoveQ #25,D0              ; say that memory is full...
  1137.               _SysError                 ; and call syserror
  1138. ; If it returns better go into the debugger since its not supposed to return
  1139.               _Debugger                 ; Hey! sysError came back!
  1140. ;
  1141. CallNewHand   _NewHandle
  1142.               bne.S  MemFull            ; could not get the memory, just die
  1143.               rts
  1144. What’s happening is that you’re running out of memory somehow (several places call MemFull, not just the above place), so you’d need to use a stack crawl to figure out how you got there. But, the bottom line, QuickDraw has run out of memory and cannot continue; it tried to put up a system error dialog to tell the user and for some reason the machine did not get restarted and the SysError vector returned. You are now in your debugger, since QuickDraw put up the system error dialog because it could not continue.
  1145. ditherCopy not supported on LaserWriter or ImageWriter
  1146. Written:    5/31/91
  1147. Last reviewed:    11/6/91
  1148. ditherCopy is not supported on LaserWriters or ImageWriters. On a LaserWriter, ditherCopy gets misinterpreted and inverts the image. On an ImageWriter it’s treated as a srcCopy. The ImageWriter driver doesn’t support color grafPorts, which is the only way to do the pixel image required for ditherCopy. Use srcCopy instead for both printers.
  1149. Macintosh Color QuickDraw CalcCMask and SeedCFill clarified
  1150. Written:    1/1/90
  1151. Last reviewed:    11/21/90
  1152. I’m having trouble using CalcCMask and SeedCFill. What am I doing wrong?
  1153. ___
  1154. There is some confusion regarding the use of the Macintosh Color QuickDraw routines CalcCMask and SeedCFill, which are analogous to the older CalcMask and SeedFill. Much of the confusion was caused by early documentation errors. Be sure you have the release version of Volume 5 of Inside Macintosh and version 2.0 or later of the MPW interface files.
  1155. The correct interface for CalcCMask is:
  1156. PROCEDURE CalcCMask(srcBits, dstBits: BitMap;
  1157.           srcRect, dstRect: Rect;
  1158.           seedRGB:     RGBColor;
  1159.           matchProc:    ProcPtr;
  1160.           matchData:    LongInt);
  1161. The correct interface for SeedCFill is:
  1162. PROCEDURE SeedCFill(srcBits, dstBits: BitMap;
  1163.           srcRect, dstRect: Rect;
  1164.           seedH, seedV:   INTEGER;
  1165.           matchProc:    Ptr;
  1166.           matchData:    LongInt);
  1167. Each routine calculates a one-bit deep BitMap representing either the mask or the fill area depending upon the routine. In both cases, the source BitMap may be either a BitMap or a pixmap, but the destination must be a BitMap, because it must have a depth of one-bit.
  1168. It is difficult to pass a pixmap for the source parameter because of Pascal’s type checking. To get around this difficulty, you can declare a new type:
  1169.      BitMapPtr  =  ^BitMap
  1170. then use it to coerce the pixmap as follows:
  1171.      SeedCFill(BitMapPtr(@myPixMap)^, ...);
  1172. If you have a PixMapHandle, do the following:
  1173.      SeedCFill(BitMapPtr(myPixMapHandle^)^, ...);
  1174. If you are using a GrafPort (or a window), you can pass myWindow^.portBits and not have to worry about whether the port uses a BitMap or a PixMap.
  1175. Most of the other parameters are explained in detail in Inside Macintosh. To use the matchProc and the matchData parameters, though, you need more information.
  1176. As stated in Inside Macintosh, the matchProc parameter is a pointer to a routine that you would like to use as a custom SearchProc. To better understand how this is used, it is helpful to know how SeedCFill and CalcCMask actually work.
  1177. Both routines start by creating a temporary BitMap which, by definition, is one bit deep. The source PixMap (or BitMap) is then copied to the temporary BitMap using CopyBits. This copy causes the image to be converted to a depth of one-bit. Now with a normal black-and-white image, the standard CalcMask or SeedFill routine is used to generate the destination BitMap.
  1178. Most of the real work is done in the original call to CopyBits, which maps the PixMap image to a monochrome BitMap equivalent. For each color in the source PixMap, CopyBits will map it to either black or white. Which colors map to black and which ones to white is determined by the SearchProc.
  1179. SeedCFill installs a default SearchProc that maps all colors to black except for the color of the pixel at (seedH,seedV). SeedFill then calculates as usual the fill mask for the white bits .
  1180. The default SearchProc for CalcCMask maps all colors to white except the color passed in the seedRGB parameter. The seedRGB parameter, then, would be the color of the item that you wanted to “lasso.”
  1181. But suppose you want to fill over all colors that were shades of green, not just the particular shade of green at (seedH,seedV). Or maybe you want to fill over all colors that are lighter than 50% brightness. Or maybe you want to use dark colors as edge colors for CalcCMask. To do such things, you need to pass a pointer to your own SearchProc in the matchProc parameter.
  1182. Because your matchProc is just a custom search procedure for the Color Manager, it should be declared as one, but Volumes I-V of Inside Macintosh have documented this routine incorrectly. The correct declaration for a custom SearchProc is as follows:
  1183. FUNCTION SearchProc(VAR RGB: RGBColor;
  1184.           VAR result: LongInt) : Boolean;
  1185. Normally, as each SearchProc is installed, it is added to the head of the SearchProc chain, so that it is called before all of the other ones which were already installed. When a SearchProc is installed, it can do one of three things:
  1186. 1. Completely ignore the call by returning FALSE and not modifying any of the input parameters;
  1187. 2. Completely handle the call by setting the result parameter to be the index into the color table that matches (according to your rules) the RGB parameter. In that case, the SearchProc returns TRUE;
  1188. 3. Partially handle the call by modifying the RGB parameter, then returning FALSE.
  1189. In cases 1 and 3, the Color Manager continues down the SearchProc chain until it finds one that returns TRUE. If none of the custom routines handle the call, then the built-in default routine is used. In case 3, you can change the RGB color that is being matched. For example, if you want all shades of green to map to pure green, modify the RGB color, then return FALSE, letting the Color Manager find the index of that green in the color table.
  1190. In case 2, you return TRUE to indicate that you handled the call, and you return the color table index in the result parameter. The Color Manager then uses that index. For example, if you want to substitute white for all colors that can’t be matched exactly in the color table, then each time you get called you either return the index into the color table of the exact color, or 0 (which is the index for white) for all other colors.
  1191. A custom SearchProc for SeedCFill and CalcCMask should always return TRUE because the default Color Manager SearchProc usually doesn’t make sense. Because SeedCFill and CalcCMask are using CopyBits to copy to a 1-bit BitMap, you need to set the result to be either 0 or 1 (the only possible values in a 1-bit BitMap). A result of 0 is white, and a result of 1 is black.
  1192. All colors for SeedCFill that should be “filled over” would generate a result of 0 (white), and all colors that stop the fill generate a 1 (black). SeedFill is then called to fill the white area. All colors for CalcCMask that you want to form boundaries should generate results of 1 (black).
  1193. When your SearchProc gets called, the gdRefCon field of the current GDevice (theGDevice^^.gdRefCon) contains a pointer to the following record:
  1194.     matchRec  =  RECORD
  1195.       red:       Integer;
  1196.       green:     Integer;
  1197.       blue:      Integer;
  1198.       matchData: LongInt;
  1199.     END;
  1200. The red, green, and blue parameters for SeedCFill are the values of the color of the pixel at (seedH,seedV). For CalcCMask, they are the fields from the seedRGB parameter. Your SearchProc can use this information to decide which colors are “fill-over” colors and which colors are “boundary” colors. For example, if you always set (seedH,seedV) to be the mouse point, your SearchProc then bases its decisions using the color of the pixel under the cursor. For example, the user clicks on a shade of green, so all shades of green get filled over.
  1201. The matchData field contains the value that you passed into the SeedCFill or CalcCMask routines in the matchData parameter. The use of this field is completely user-defined. For example, since your SearchProc routine may be a separate module, you might want to use this field to pass a handle to your variables. This field can contain a handle, a pointer, a long integer, or whatever; or you can just ignore this field altogether.
  1202. Warning: There are some features of CalcCMask and SeedCFill you should be aware of. To understand them, you should be familiar with the use of CalcMask and SeedFill, which are described in the QuickDraw chapter of IM IV.
  1203. CalcCMask and SeedCFill both use a parameter set that is very similar to the one used by CopyBits. CalcMask and SeedFill, however, are a different story. Instead of passing bitmaps and rectangles to SeedFill and CalcMask, these routines use an unusual set of parameters that describe the memory to be operated upon in terms of pointers, height, width, and offsets to the next row (rowBytes). Although these parameters are fairly easy to calculate, there are some limitations.
  1204. The most restrictive limitation is that the width of the rectangle used must be an even multiple of 16 bits. This limitation exists because the width of the rectangle is passed to SeedFill and CalcMask as a number of words (2 bytes). When calculating this parameter, SeedCFill and CalcCMask round down to an even word boundary. This rounding means that the rectangles you pass to CalcCMask and SeedCFill should be an even multiple of 16 pixels in width. If they are not, then the rightmost portion of the mask will be garbage.
  1205. To figure out the color of the pixel at (seedH,seedV), SeedCFill calls GetCPixel. GetCPixel finds the color of the pixel at (h,v) in the current port. Therefore, if you pass a PixMap which is not the PixMap of the current port you will get bizarre results. In other words, seedH and seedV are expressed in the local coordinates of the current port, not the coordinate of the source PixMap.
  1206. You have two methods to make it work. First, always pass the PixMap of the current port as the source parameter. If you are using an off-screen PixMap, it is a good idea to have an associated port for it, and then call SetPort, passing it a pointer your off-screen port, before you call SeedCFill.
  1207. The second method involves letting SeedCFill get some wrong value for the color at (seedH,seedV) then using your own custom SearchProc to do the real work. The default SearchProc for SeedCFill relies on getting the correct color, but your SearchProc doesn’t have to.
  1208. SeedCFill also makes the assumption that the seedH and seedV parameters are in the local coordinate system of the destination BitMap. This assumption comes into play when SeedCFill calculates the seedH and seedV parameters for SeedFill.
  1209. All this means that SeedCFill only works correctly if the source PixMap, destination PixMap, and current port all use the same coordinate system. Because of the above problem, this is almost automatic since the current port’s portRect and the bounds of the source PixMap have to be the same anyway.
  1210. The easiest way to make all this work is to have your main port be an even multiple of 16 pixels wide. Then, make sure that your source and destination structures (PixMap or BitMap) are all the same size and all have origins of (0,0).
  1211. System 7.0ß1 BitMapToRgn limitation
  1212. Written:    1/1/90
  1213. Last reviewed:    12/7/90
  1214. BitMapToRegion does not work as described in the Macintosh Tech Note “32-Bit QuickDraw: Version 1.2 Features” for a PixMap with baseAddr = (NuBus address). Which calls support PixMap 32-bit base addressing with pmVersion = 4?
  1215. ___
  1216. As of System 7.0ß1, BitMapToRgn cannot handle a bitmap whose base address is in the NuBus address space or any bitmap that requires 32-bit addressing. The problem will be fixed for System 7’s final release. BitMapToRgn seems to be the only call that doesn’t yet support 32-bit addressed bitmaps.
  1217. X-Ref:
  1218. DTS Macintosh Technical Note “32-Bit QuickDraw: Version 1.2 Features”
  1219. Macintosh Color QuickDraw and packed PICTs
  1220. Written:    1/1/90
  1221. Last reviewed:    12/7/90
  1222. Does Macintosh 32-Bit QuickDraw support packed PICTs? What’s the technique for saving packed PICT formats? What compression schemes are supported?
  1223. ___
  1224. Color QuickDraw has always supported packed PICTs. See Inside Macintosh, Volume V, for details on how CLUT PixMaps are packed. Under 32-Bit QuickDraw, to pack direct RGB PixMaps in PICTs, call CopyBits with the packType field in the source PixMap set to one of the following constants that apply to direct RGB PixMaps:
  1225. 0 - default packing (pixelSize 16 defaults to packType 3 and pixelSize 32 defaults to packType 4)
  1226. 1 - no packing
  1227. 2 - remove pad byte (32-bit pixels only)
  1228. 3 - run-length encoding by pixel size chunks (16-bit pixels only)
  1229. 4 - run-length encoding, all of one component at the time, one scan line at a time (24-bit pixels only)
  1230. Scheme 4 will store the alpha channel also if cmpCount is set to to four. PackSize is not used and should be set to zero for compatibility reasons. These are the only compression techniques supported at this time.
  1231. Macintosh PICT color picture file format
  1232. Written:    1/1/90
  1233. Last reviewed:    11/21/90
  1234. Is there a general file format for color pictures that is common to all of the color paint programs? If so, where is it documented?
  1235. ___
  1236. Apple supports (and encourages developers to support) one file type for pictures: the PICT file type. Most paint-type programs handle PICT files.
  1237. A PICT file is composed of two parts in its data fork; the first 512 bytes for the file header which contain application-dependent information. You have to contact the individual publishers to find out their particular data structures. For example, you can contact Claris Technical Support at AppleLink CLARIS.TECH or (415) 962-0371 for the file header MacDraw writes to its files.
  1238. The rest of the data in the file is picture data as created by Macintosh QuickDraw with OpenPicture. You can find the information about this data in Volume V of Inside Macintosh (pages 84-105); this section also shows how to read/write PICT files.
  1239. You can also check the Macintosh Tech Note “Displaying Large PICT Files” for more details on the subject.
  1240. X-Refs:
  1241. DTS Macintosh Technical Note “QuickDraw’s Internal Picture Definition”
  1242. DTS Macintosh Technical Note “Displaying Large PICT Files”
  1243. Mac PixMap is clipped to visRgn defined by screenBits.bounds
  1244. Written:    1/1/90
  1245. Last reviewed:    11/21/90
  1246. I’m drawing into a large offscreen bitmap (PixMap), but anything drawn outside the 640 by 480 pixel Macintosh screen area doesn’t get written to the PixMap. Why not?
  1247. ___
  1248. When you create a new port with OpenPort or OpenCPort the visRgn is initialized to the rectangular region defined by screenBits.bounds (IM I:163). If your port has a large portRect, any drawing will be clipped to the visRgn and you will lose any drawing outside of the screenBits.bounds rectangle.
  1249. To correct this set the visRgn of the port to coincide with your port’s portRect after creating the port.
  1250. Also note that OpenPort initializes the clipRgn to a wide-open rectangular region (-32768, -32768, 32767, 32767). Some operations, like OpenPicture, can fail with this setup, so try setting clipRgn to a smaller rectangle.
  1251. X-Refs:
  1252. DTS Macintosh Technical Note “Pictures and Clip Regions”
  1253. DTS Macintosh Technical Note “Drawing into an Off-Screen Pixel Map”
  1254. Using Mac System 7 OpenCPicture for higher resolution
  1255. Written:    1/1/90
  1256. Last reviewed:    12/7/90
  1257. We want to use OpenCPicture for higher resolution, not for color per se. Can OpenCPicture in System 7 be used with non-Color as well as Color QuickDraw Macintosh computers?
  1258. ___
  1259. Yes, with System 7, OpenCPicture can be used to create extended PICT2 files from all Macintosh computers. Under System 6.0.7 or later, you must test for 32-Bit QuickDraw before using OpenCPicture. You can do this by calling Gestalt with the gestaltQuickDrawVersion selector. If it returns gestalt32BitQD or greater, then 32-Bit QuickDraw is installed.
  1260. How to identify 32-Bit QuickDraw version
  1261. Written:    1/1/90
  1262. Last reviewed:    11/21/90
  1263. How can my program find out which version of Macintosh 32-Bit QuickDraw is running?
  1264. ___
  1265. The following code snippet demonstrates how to use the Gestalt Manager to determine which version of 32-Bit QuickDraw is installed. There is no way to determine the version of 32-Bit QuickDraw before Gestalt. For 32-Bit QuickDraw version 1.2, Gestalt returns 2.2. IM VI describes the Gestalt Manager in detail.
  1266. #defineTRUE0xFF
  1267. #defineFALSE0
  1268. #define Gestalttest0xA1AD
  1269. #define NoTrap0xA89F
  1270. main()
  1271. {
  1272. OSErrerr;
  1273. longfeature;
  1274. if ((GetTrapAddress(Gestalttest) != GetTrapAddress(NoTrap))) {
  1275. err = Gestalt(gestaltQuickdrawVersion, &feature);
  1276. if (!err) {
  1277. if ((feature & 0x0f00) == 0x0000)
  1278. printf ("We have Original QuickDraw version 0.%x\n", (feature & 0x00ff));
  1279. else if ((feature & 0x0f00) == 0x0100)
  1280. printf ("We have 8 Bit QuickDraw version 1.%x\n", (feature & 0x00ff));
  1281. else if ((feature & 0x0f00) == 0x0200)
  1282. printf ("We have 32 Bit QuickDraw version 2.%x\n", (feature & 0x00ff));
  1283. else
  1284. printf ("We don't have QD\n");
  1285. }
  1286. else
  1287. printf ("Gestalt err = %i\n",err);
  1288. }
  1289. else
  1290. printf ("No Gestalt\n");
  1291. }
  1292. Macintosh QDError function under System 6 and System 7
  1293. Written:    1/1/90
  1294. Last reviewed:    12/7/90
  1295. Under what System 7 and System 6 conditions is it legal to call the Macintosh QDError function?
  1296. ___
  1297. Under System 7, QDError can be called from all Macintosh computers. (System 7 supports RGBForeColor, RGBBackColor, GetForeColor, and GetBackColor for all Macintosh computers as well.) On a non-Color QuickDraw Macintosh, QDError always returns a “no error.” Under System 6, QDError cannot be used for non-Color QuickDraw Macintosh systems.
  1298. Macintosh CopyBits transfer modes changed for System 7
  1299. Written:    1/1/90
  1300. Last reviewed:    12/7/90
  1301. Why do some Macintosh CopyBits transfer modes produce different results for System 7 than for System 6?
  1302. ___
  1303. Under System 6, the srcOr, srcXor, srcBic, notSrcCopy, notSrcOr, notSrcXor, and notSrcBic transfer modes do not produce the same effect for a 16- or 32-bit (direct) pixel map as for an 8-bit or shallower (indexed) pixel map. With Color QuickDraw these classic transfer modes on direct pixel maps aren’t color based; they’re pixel value based. Color QuickDraw performs logical operations corresponding to the transfer mode on the source and destination pixel values to get the resulting pixel value.
  1304. For example, say that a multicolored source is being copied onto a black and white destination using the srcOr transfer mode, and both the source and destination are 8 bits per pixel. Except in unusual cases, the pixel value for black on an indexed pixel map has all its bits set, so an 8-bit black pixel has a pixel value of $FF. Similarly, the pixel value for white has all its bits clear, so an 8-bit white pixel has a pixel value of $00. CopyBits takes each pixel value of the source and performs a logical OR with the corresponding pixel value of the destination. Using OR to combine any value with 0 results in the original value, so using OR to combine any pixel value with the pixel value for white results in the original pixel value.  Using OR to combine any value with 1 results in 1, so using OR to combine any pixel value with the pixel value for black results in the pixel value for black. The resulting image shows the original image in all areas where the destination image was white and shows black in all areas where the destination image was black.
  1305. Take the same example, but this time make the source and destination 32 bits per pixel. The direct-color pixel value for black is $00000000 and the direct-color pixel value for white is $00FFFFFF. CopyBits still performs a logical OR on the source and destination pixel values, but notice what happens in this case. Using OR to combine any source pixel value with the pixel value for white results in white, and using OR to combine any source pixel value with the pixel value for black results in the original color. The resulting image shows the original image in all areas where the destination image was black and shows white in all areas where the destination image was white—roughly the opposite of what you see on an indexed pixel map.
  1306. The newer transfer modes addOver, addPin, subOver, subPin, adMax, and adMin work consistently at all pixel depths, and often, though not always, correspond to the theoretical effect of the old transfer modes. For example, the adMin mode works similarly to the srcOr mode on both direct and indexed pixel maps. Also, 1-bit deep source pixel maps work consistently and predictably regardless of the pixel depth of the destination even with the old transfer modes.
  1307. Under System Software 7.0, the old transfer modes now perform by calculating with colors rather than pixel values. You’ll find that transfer modes like srcOr and srcBic work much more consistently even on direct pixel maps.
  1308. Which QuickDraw versions support SetEntries
  1309. Written:    3/3/92
  1310. Last reviewed:    6/30/92
  1311. I’m calling SetEntries to update the onscreen CLUT. Who implements this call? Does 32-Bit QuickDraw? In other words, does the 32-Bit QuickDraw INIT need to be around for this to work? What about monochrome machines? 
  1312. I’m creating offscreen buffers by hand instead of using GWorlds. Is this the proper way of doing offscreen buffering when we don’t want to require the user to have 32-Bit QuickDraw?
  1313. ___
  1314. SetEntries is part of the Color Manager, which exists with all Color QuickDraw versions. A good rule of thumb to follow is that if it is documented in Inside Macintosh Volume V, you don’t need 32-Bit QuickDraw to use it. Inside Macintosh Volume V documents standard Color QuickDraw. SetEntries does not work on monochrome Macintosh models, including the Classic II, SE, and PowerBooks.
  1315. Offscreen buffering: You should always use GWorlds if they exist; use Gestalt to test for them. This will assure that you can take advantage of the latest speed improvements. It is important to remember that under system 7 NewGWorld and accompanying calls are present in all Macintosh computers including b&w systems such as Classic and PowerBook 100 systems.
  1316. Macintosh pixel map maximum rowBytes change
  1317. Written:    4/22/91
  1318. Last reviewed:    6/10/91
  1319. The Color QuickDraw section of Inside Macintosh Volume VI states that the restriction on the rowBytes field in a pixMap has been relaxed from $2000 to $4000. When did this happen? Is it true for all 32-bit QuickDraw versions? This affects our user configuration recommendations.
  1320. ___
  1321. The maximum rowBytes extension to $3FFF or less applies only to 32-bit QuickDraw. Using PixMaps with rowBytes greater than $1FFF when 32-bit QuickDraw is not present is likely to cause problems such as garbage images or system crashes. Remember that 32-bit QuickDraw is always present under System 7.0.
  1322. Use assembly to flip a 24-bit off-port color PixMap
  1323. Written:    5/7/91
  1324. Last reviewed:    7/25/91
  1325. What’s the best approach to horizontally flip a 24-bit off-port color PixMap?
  1326. ___
  1327. Unfortunately, you won’t be able to use CopyBits for this kind of procedure; you’ll have to write your own routine to move each pixel. I’d suggest doing this in assembly language to squeeze the best possible performance out of your code.
  1328. Construct a 'clut' instead of changing b/w palette entries
  1329. Written:    6/10/91
  1330. Last reviewed:    8/1/91
  1331. How can I change the first and last (white and black) entries in a Macintosh palette?
  1332. ___
  1333. The answer to your question about changing the black and white entries in a palette is a little strange. You can’t simply change the palette associated with an on-screen window, because too many portions of the Toolbox/OS assume that the first entry is white and the last entry is black.
  1334. However, what you can do is create an off-screen GWorld and construct a 'clut' for it that does what you want. Creating the 'clut' is fairly straightforward:
  1335. /* Making a reversed gray-scale color table */
  1336. CTabHandle offColors;
  1337. offColors = (CTabHandle) NewHandleClear (sizeof (ColorTable) + 255 *
  1338.               sizeof (ColorSpec));
  1339. (**offColors).ctSize = 255;
  1340. for (index = 0; index <= (**offColors).ctSize; index++)
  1341.   {
  1342.     (**offColors).ctTable [index].value = index;
  1343.     (**offColors).ctTable [index].rgb.red = (index << 8) | index;
  1344.     (**offColors).ctTable [index].rgb.green = (index << 8) | index;
  1345.     (**offColors).ctTable [index].rgb.blue = (index << 8) | index;
  1346.   }
  1347. (**offColors).ctFlags = 0;
  1348. (**offColors).ctSeed = GetCTSeed ();
  1349. Note that using this 'clut' with an off-screen GWorld will work fine _except_ if you attempt to draw text into the GWorld. Apparently drawing text off screen carries the same assumptions that all drawing does on screen.
  1350. Once you have done your off-screen drawing with the reversed 'clut' as described above, all that remains is to CopyBits from your off-screen GWorld to your on-screen window. Your on-screen window will need the appropriate palette. Fortunately, constructing that palette from the 'clut' is trivial:
  1351. /* Make a palette out of it */
  1352. aPalette = NewPalette (offColors, (**offColors).ctSize + 1, pmTolerant, 0);
  1353. Attaching this palette to the window will cause the correct remapping to occur when you CopyBits from the GWorld to the window, and everything should look just fine.
  1354. Why PlotCIcon requires GetCIcon instead of Get1Resource
  1355. Written:    4/26/91
  1356. Last reviewed:    6/17/91
  1357. Why do I have to use GetCIcon(resID) instead of Get1Resource('cicn',resID) forPlotCIcon to work correctly?
  1358. ___
  1359. You apparently thought something that, at first, I thought also: that GetCIcon(resID) is just a utility routine that translates to Get1Resource('cicn',resID). However, this is not the case; GetCIcon not only gets the 'cicn' resource, but it also performs some minor surgery on the results, fills in some placeholder fields in the resource data, and the like. Basically, PlotCIcon can’t work without the things that GetCIcon does.
  1360. CopyBits maps source PixMap colors to GDevice inverse table
  1361. Written:    4/3/91
  1362. Last reviewed:    6/17/91
  1363. I’m trying to draw off screen so I made my own CGrafPort, PixMap, and color table, but when I draw into it, the colors come out all wrong. What’s going on here?
  1364. ___
  1365. It’s a very common misconception that CopyBits maps the colors available in the source PixMap’s color table to the colors available in the destination PixMap’s color table.
  1366. What actually happens is that CopyBits maps the colors in the source PixMap to the colors available in the current GDevice’s inverse table. See Inside Macintosh, Volume V, pages 137 through 139 for a description of inverse tables. Inverse tables is a backwards color table. With a color table, you use a pixel value as an index into the table to return a color. With an inverse table, you use a color-like value as an index into the table to return a pixel value. When CopyBits maps colors from one pixel map to another, it takes a source pixel value, uses the source PixMap’s color table to get the corresponding color, and uses that color as an index into the current GDevice’s inverse table to get the pixel value of the closest color in the destination PixMap’s color table.
  1367. Generally speaking, every conceivable color table has exactly one conceivable inverse table. If you alter the contents of a color table, then the inverse table must likewise be altered. It’s just like numbers: for any number you give me, I can give you its negative. For any color table you give me, MakeITable can give you its inverse table. MakeITable is documented in Inside Macintosh, Volume V, page 142.
  1368. Think of the current GDevice as an implied parameter to CopyBits. If you don’t deal with GDevices at all, then the current GDevice is always the main screen’s GDevice as far as you’re concerned. Color QuickDraw often switches between different screens’ GDevices so that you can draw to multiple screens, but that’s all handled behind your back. If you create a PixMap, give it a color table, and CopyBits to it, then the main screen’s GDevice’s inverse table is used to map colors from the source PixMap. That’s OK as long as your destination PixMap’s color table is compatible with the main screen’s inverse table. If you change the depth and/or color table of the main screen, and then still CopyBits to this same PixMap with the same old depth and color table, then things won’t work correctly because the main screen’s GDevice’s inverse table changes, making it incompatible with your destination PixMap’s color table. This problem usually manifests itself as incorrect colors, but it can result in crashes.
  1369. To fix this, you’ll have to remove your reliance on the main screen’s GDevice.To do that you’ll have to make your own GDevice. There’s a routine called NewGDevice, but it always makes the GDevice in the system heap. Instead, you should just call NewHandle to allocate a GDevice record yourself. Here’s what the fields should hold:
  1370. gdRefNum - The GDevice has no driver, so set this to zero.
  1371. gdID - It doesn’t matter what this is set to — might as well set it to zero.
  1372. gdType - Set this to 2 if the off-screen uses direct colors (16 or 32 bits per pixel) or 0 if the off-screen uses a color table (1 through 8 bits per pixel).
  1373. gdITable - Allocate a small (maybe just a 2-byte) handle for this field. After you’re done setting up this GDevice and your off-screen PixMap, color table (if any) and CGrafPort, then set this GDevice as the current GDevice by calling SetGDevice. Then call MakeITable, passing it NIL for both the color table and inverse table parameters, and 0 for the preferred inverse table resolution.
  1374. gdResPref - I’d guess that more than 99.9% of all inverse tables out there have a resolution of 4. Unless you have some reason not to, I’d recommend the same here.
  1375. gdSearchProc - Set to NIL. Use AddSearch if you want to use a SearchProc.
  1376. gdCompProc - Set to NIL. Use AddComp if you want to use a CompProc.
  1377. gdFlags - Set to 0 initially, and then use SetDeviceAttribute after you’ve set up the rest of this GDevice.
  1378. gdPMap - Set this to be a handle to your off-screen PixMap.
  1379. gdRefCon - Set this to whatever you want.
  1380. gdNextGD - Set this to nil.
  1381. gdRect - Set this to be equal to your off-screen PixMap’s bounds.
  1382. gdMode - Set this to -1. This is intended for GDevices with drivers anyway.
  1383. gdCCBytes - Set to 0.
  1384. gdCCDepth - Set to 0.
  1385. gdCCXData - Set to 0.
  1386. gdCCXMask - Set to 0.
  1387. gdReserved - Set to 0.
  1388. For gdFlags, you should use SetDeviceAttribute to set the noDriver bit and the gDevType bit. You should set the gDevType bit to 1 even if you have a monochrome color table. The 0 setting was only used when monochrome mode was handled by the video driver, and 32-Bit QuickDraw eliminated that convention. Your GDevice doesn’t have a driver anyway.
  1389. Once this is done, the GDevice and the off-screen PixMap should be treated as inseparable. When you CopyBits or draws into the PixMap, first call SetGDevice to set its GDevice as the current GDevice. When that’s done, call SetGDevice to restore the previous GDevice. Doing this insulates you from changes in a screen’s GDevice.
  1390. If you alter your PixMap’s color table, you should make sure you update the ctSeed of that color table, either by assigning to it the result of GetCTSeed (documented on page 143 of Inside Macintosh, Volume V) or by passing a handle to the color table to CTabChanged. The next time that PixMap is drawn into, Color QuickDraw will update your GDevice’s inverse table automatically when it realizes that the ctSeed is different from the current GDevice (which had better be yours) inverse table’s iTabSeed.
  1391. GWorlds work this way on Color QuickDraw machines. Every GWorld comes with a PixMap and a GDevice. When you call SetGWorld, that sets both the GWorld and its GDevice as current.
  1392. How Macintosh system draws small color icons
  1393. Written:    3/31/92
  1394. Last reviewed:    5/21/92
  1395. The code I added to my application’s MDEF to plot small icons in color works except for when I hold the mouse over an item with color. The color of the small icons is wrong because it’s just doing an InvertRect. When I drag over the Apple menu, the menu inverts behind the icon but the icon is untouched. Is this done by brute force, redrawing the small icon after every InvertRect?
  1396. ___
  1397. As you figured out, the Macintosh system draws color icons, such as the Apple icon on the menu bar, every time the title has to be inverted.
  1398. The actual sequence of calls is (more or less) as follows: first InvertRect is called to black the menu title and then PlotIconID is called to draw the icon in its place. The advantage of using PlotIconID is that you don’t have to worry about the depth and size of the icon being used. The system picks the best match from the family whose ID is being passed, taking into consideration the target rectangle and the depth of the device(s) that will contain the icon’s image.
  1399. The Icon Utilities call PlotIconID is documented in the Macintosh Technical Note, “Drawing Icons the System 7 Way.” Just in case you don’t have your stack at hand, the interface is:
  1400.     IconAlignmentType    =    INTEGER;
  1401.     IconTransformType    =    INTEGER;
  1402.     FUNCTION PlotIconID(theRect: Rect;
  1403.                         align: IconAlignmentType;
  1404.                         transform: IconTransformType;
  1405.                         theResID: INTEGER): OSErr;
  1406.         INLINE    $303C, $0500, $ABC9;
  1407.     
  1408. typedef short    IconAlignmentType;
  1409. typedef short    IconTransformType;
  1410. pascal OSErr PlotIconID(const Rect *theRect,
  1411.                             IconAlignmentType align,
  1412.                             IconTransformType transform,
  1413.                             short theResID)
  1414.     = {0x303C, 0x0500, 0xABC9};
  1415. Please refer to the Tech Note referenced above for more details on using the calls.
  1416. Spooling and preserving Macintosh QuickDraw pixmap depth
  1417. Written:    2/11/92
  1418. Last reviewed:    9/15/92
  1419. When spooling a picture that contains a PixMap into a window, how and when is the depth of the PixMap in the picture converted to the depth of the screens the window is on?
  1420. ___
  1421. When spooling in a picture, if QuickDraw encounters any bitmap opcode it allocates a pixmap of the same depth as the data contained in the bitmap opcode, it expands the data into the temporary pixmap, and then it calls StdBits. StdBits is what triggers the depth and color conversions as demanded by the color environment (depth, color table, B&W settings) of the devices the target port may span (as when a window crosses two or more screens).
  1422. If there’s not enough memory in the application heap or in the temporary memory pool, QuickDraw bands the image down to one scan line and calls StdBits for each of these pieces. Note that if you’re providing your own bits proc then QuickDraw will call it instead of StdBits.
  1423. This process is the same when the PICT is in memory, with the obvious exception that all the PICT data are present; all the color mapping occurs when StdBits does its stuff.
  1424. Determining the resolution of a PICT
  1425. Written:    6/10/92
  1426. Last reviewed:    9/15/92
  1427. In a version 2 picture, the picFrame is the rectangular bounding box of the picture, at 72 dpi. I would like to determine the bounding rectangle at the stored resolution or the resolution itself. Is there a way to do this without reading the raw data of the PICT resource itself?
  1428. ___
  1429. With regular version 2 PICTs (or any pictures), figuring out the real resolution of the PICT is pretty tough. Applications use different techniques to save the information. But if you make a picture with OpenCPicture, the resolution information is stored in the headerOp data, and you can get at this by searching for the headerOp opcode in the picture data (it’s always the second opcode in the picture data, but you still have to search for it in case there are any zero opcodes before it). Or you can use the Picture Utilities Package to extract this information.
  1430. With older picture formats, the resolution and original bounds information is sometimes not as obvious or easily derived. In fact, in some applications, the PICT’s resolution and original bounds aren’t stored in the header, but rather in the pixel map structure(s) contained within the PICT.
  1431. To examine these pixMaps, you’ll first need to install your own bitsProc, and then manually check the bounds, hRes, and vRes fields of any pixMap being passed. In most cases the hRes and vRes fields will be set to the Fixed value 0x00480000 (72 dpi); however, some applications will set these fields to the PICT’s actual resolution, as shown in the code below.
  1432. Rect            gPictBounds;
  1433. Fixed            gPictHRes, gPictVRes;
  1434. pascal void ColorBitsProc (srcBits, srcRect, dstRect, mode, 
  1435.     maskRgn)
  1436. BitMap        *srcBits;
  1437. Rect            *srcRect, *dstRect;
  1438. short            mode;
  1439. RgnHandle    maskRgn;
  1440. {
  1441.     PixMapPtr    pm;
  1442.     pm = (PixMapPtr)srcBits;
  1443.     gPictBounds = (*pm).bounds;
  1444.     gPictHRes = (*pm).hRes;        /* Fixed value */
  1445.     gPictVRes = (*pm).vRes;        /* Fixed value */
  1446. }
  1447. void FindPictInfo(picture)
  1448. PicHandle picture;
  1449. {
  1450.     CQDProcs        bottlenecks;
  1451.     SetStdCProcs (&bottlenecks);
  1452.     bottlenecks.bitsProc = (Ptr)ColorBitsProc;
  1453.     (*(qd.thePort)).grafProcs = (QDProcs *)&bottlenecks;
  1454.     DrawPicture (picture, &((**picture).picFrame));
  1455.     (*(qd.thePort)).grafProcs = 0L;
  1456. }
  1457. Adding Color With CopyBits
  1458. Imaging    M.IM.ColorCopyBits
  1459. Revised by        March 1988
  1460. Written by:    Chris Derossi    November 1987
  1461. Inside Macintosh Volume V states that the foreground and background colors are applied to an image during a CopyBits or CopyMask call. Accidental use of this feature can create bizarre coloring effects. This note explains what happens, how to avoid problems, and how to use it.
  1462. What Happens
  1463. Color QuickDraw has a feature that will allow you to convert a monochrome image to a color image. During a CopyBits or CopyMask call, if the foreground and background colors are not black and white, respectively, Color QuickDraw performs the following operation on every pixel being copied:
  1464.     NOTE: color table index = pixel value
  1465.     s = color table index of source pixel
  1466.     fg = color table index of foreground color
  1467.     bg = color table index of background color
  1468.     ColoredPixelValue = (NOT(s) AND bg) OR (s AND fg)
  1469. If your source image contains only black and white pixels, then all black pixels would become the foreground color and all white pixels would become the background color. This is because the color table index for white is all zeros and the color table index for black is all ones.
  1470. For example, suppose your source image was a 4-bit deep color PixMap. Then the color table index for white (in binary) is 0000 and the index for black is 1111. And let’s suppose that your foreground color is green with an index of 1101 while your background color is red with an index of 0011. Then for the black pixels, the above procedure produces:
  1471.     ColoredPixelValue = (NOT(1111) AND 0011) OR (1111 AND 1101)
  1472.          1101         = (  0000    AND 0011) OR (1111 AND 1101)
  1473. And the operation on the white pixels yields:
  1474.     ColoredPixelValue = (NOT(0000) AND 0011) OR (0000 AND 1101)
  1475.          0011         = (  1111    AND 0011) OR (0000 AND 1101)
  1476. Possible Problems
  1477. This colorizing will only work on 2-color (i.e. black and white) images, and then only if those colors occupy the first and last entries in the color table. Trying to colorize colors that are not the first and last color table entries will yield unexpected results.
  1478. This is mainly due to the fact that the colorizing algorithm uses a pixel’s color table index value rather than its actual RGB color. To illustrate this, let’s assume that foreground and background colors are as above, and your image contains yellow with a color table index of 1000. The colorizing operation would give:
  1479.     ColoredPixelValue = (NOT(1000) AND 0011) OR (1000 AND 1101)
  1480.          1011         = (  0111    AND 0011) OR (1000 AND 1101)
  1481. Since the color table may have any RGB color at the resulting index position, the final color may not even be close to the source, foreground, or background colors.
  1482. Similar things occur if you are trying to colorize a black and white image when white and black do not occupy the first and last positions in the color table.
  1483. The bottom line rules for CopyBitsing in a color environment are these:
  1484. •    Thou shalt set thy background color to white and thy foreground color to black before calling CopyBits or CopyMask, unless thou art coloring a monochrome image.
  1485. •    Thou shalt, when colorizing, make sure that the first color table entry is white and the last     color table entry is black.
  1486. The second rule is easy to follow because the default color tables are constructed properly, and if you are using the Palette Manager (and you are, right?) then it will make sure that the color tables obey this rule.
  1487. How To Colorize—An Example
  1488. This code fragment shows how to implement a color fill, like the paint bucket in MacPaint. It relies on three main things: SeedCFill for calculating the fill area, CopyMask for actually changing the bits, and QuickDraw colorizing.
  1489. PROCEDURE PaintBucket(where: Point; paintColor: RGBColor);
  1490.     VAR
  1491.         savedFG    : RGBColor;
  1492.         offBits    : BitMap;
  1493.     BEGIN
  1494.         {First, create an offscreen bitmap.}
  1495.         offBits.bounds := myWindow^.portRect;
  1496.         WITH offBits.bounds DO BEGIN
  1497.             offBits.rowBytes := ((right - left + 15) DIV 16) * 2;
  1498.             offBits.baseAddr := NewPtr((bottom-top) * offBits.rowBytes);
  1499.         END;
  1500.         {Check MemError here! Make sure NewPtr succeeded!}
  1501.         SeedCFill(myWindow^.portBits,offBits,myWindow^.portRect,
  1502.             myWindow^.portRect,where.h,where.v,NIL,0);
  1503.         GetForeColor(savedFG);
  1504.         RGBForeColor(paintColor);
  1505.         CopyMask(offBits,offBits,myWindow^.portBits,myWindow^.portRect,
  1506.             myWindow^.portRect,myWindow^.portRect);
  1507.         RGBForeColor(savedFG);
  1508.         DisposPtr(offBits.BaseAddr);
  1509.     END;
  1510. The variable offBits is an offscreen BitMap (not a PixMap) with bounds = myWindow^.portRect.  SeedCFill effectively creates, in the offscreen BitMap,  a monochrome image of the bits that we want to paint. Since offBits contains the exact bits that we want to paint, it is used as both the source image and the mask for CopyMask.
  1511. By setting the foreground color to the desired paint color, the result is a colorized version of the mask (the paint area) being copied onto the window’s PixMap without affecting any other bits.
  1512. Further Reference:
  1513. •    Color QuickDraw
  1514. Deaccelerated _CopyBits & 8•24 GC QuickDraw
  1515. Imaging    M.IM.GCQDCopybits
  1516. Written by:    Guillermo A. Ortiz    February 1991
  1517. This Technical Note discusses conditions that may cause _CopyBits to slow down when QuickDraw acceleration is on via the Apple 8•24 GC Display Card.
  1518. Introduction
  1519. When a drawing call is issued, GC IPC (Interprocess Communication) takes control of the call and passes it to GC QuickDraw.  After the normal port set up (which involves caching the port parameters if this is the first drawing call after the port was set), GC QuickDraw returns control to the application through the IPC and performs, in parallel, the drawing to its own monitor as well as any other monitors that may be affected by  the operation.  The application then continues its execution, probably issuing more drawing calls that get executed in the same asynchronous manner.
  1520. The result of this mode of operation is improved performance, since the application gets control back immediately after issuing the call and the GC QuickDraw moves video data to its own video buffer as well as that of other cards in a more rapid manner by using block transfers and without requiring any action by the main processor.
  1521. _CopyBits Conforms To The Same Scheme, Except…
  1522. _CopyBits conforms to the same operational scheme, but there are some instances in which GC QuickDraw cannot perform the call in parallel; in this cases it is even possible to suffer a performance loss, since the whole call may have to be completed before control is given back to the application and GC QuickDraw has to make calls and access data across the NuBus™.
  1523. The situations that compromise GC QuickDraw parallel operation are as follows:
  1524. •    When the destination device has a SearchProc installed and the source color environment is different from the destination environment.
  1525.     QuickDraw calls a SearchProc whenever the source and destination have different depths and when two indexed pixel maps have different color tables, even though their depths may be identical.  When GC acceleration is enabled, these conditions cause the following two types of behavior, dependent upon the source pixel map:
  1526. •    If the source is an indexed pixel map, then GC QuickDraw executes the part of the setup that involves calling the SearchProc, returns control to the main processor, then completes the call in parallel.  The act of calling the SearchProc before returning control makes the call slower than when no SearchProc is involved, since parallel operation does not occur throughout the whole call.
  1527. •    If the source is a direct RGB pixel map, then GC QuickDraw has to call the SearchProc for every pixel that is drawn, and the application does not regain control until after the call to _CopyBits has been completed.
  1528. •    When the source or destination is offscreen and not created using a GWorld.
  1529.     GC QuickDraw has no way to detect when an application is going to manipulate a pixel map it has created in memory, so if it has to draw to or copy from such a PixMap, GC QuickDraw has to complete the operation before returning control to the application.
  1530.     This behavior is contrary to the case when using a GWorld for offscreen environments, since in the case of a GWorld, GC QuickDraw is alerted by the call to _GetPixBaseAddr that the application is getting ready to directly change the pixels.  This is the reason why it is so important that applications call _GetPixBaseAddr every time they are about to manipulate a GWorld pixel map directly.
  1531. •    When the source PixMap has a color table that uses indexes that refer to a palette.
  1532.     QuickDraw now allows a color table to have indexes that point to entries in the palette associated with the destination window; when bit 14 in the ctFlags field is set, the value fields in the color table are treated as palette entries.  When such a PixMap is the source for _CopyBits, then GC QuickDraw has to make a number of calls to the Palette Manager as part of the setup before returning control and completing the call.
  1533.     This case is similar to that of a indexed pixel map when a SearchProc is involved; therefore, it only implies a partial loss of parallelism; it is good to keep in mind that this case can only occur when the source PixMap is indexed.
  1534. Further Reference:
  1535. •    Inside Macintosh, Volumes V & VI, Color QuickDraw
  1536. •    d e v e l o p, “Macintosh Display Card 8•24 GC:  The Naked Truth,” July 1990.
  1537. •    Technical Note #275, 32-Bit QuickDraw:  Version 1.2 Features
  1538. •    Developer Notes for the Macintosh Display Cards 4•8, 8•24 and 8•24 GC (APDA, M085TLL/A)
  1539. NuBus is a trademark of Texas Instruments.
  1540. Drawing Icons
  1541. Imaging    M.IM.DrawingIcons
  1542. Written by:    Jim Friedlander    October 1985
  1543. Using resources of type ICON allows drawing of icons in srcOr mode.  Using resources of type ICN# allows for more variety when drawing icons.
  1544. There are two different kinds of resources that contain icons: ICON and ICN#. An ICON is a 32 by 32 bit image of an icon and can be drawn using the following Toolbox Utilities calls:
  1545.     MyIconHndl:= GetIcon(iconID);
  1546.     PlotIcon(destRect,iconID);
  1547. While very convenient, this method only allows the drawing of icons in SrcOr mode (as in the MiniFinder). The Finder uses resources of type ICN# to draw icons on the desktop. Because the Finder uses ICN#s, it can draw icons in a variety of ways.
  1548. An ICN# resource is a list of 32 by 32 bit images that are grouped together. Common convention has been to group two 32 by 32 bit images together in each ICN#. The first image is the actual icon, the second image is the mask for the icon. To get a handle to an ICN#, we would use something like this:
  1549. TYPE
  1550.     iListHndl    = ^iListPtr;
  1551.     iListPtr     = ^iListStruct;
  1552.     iListStruct  = record
  1553.         icon : packed array[0..31] of Longint;
  1554.         mask : packed array[0..31] of Longint;
  1555.     End; {iListStruct}
  1556. VAR
  1557.     myILHndl      : iListHndl;            {handle to an ICN#}
  1558.     iBitMap       : BitMap;          {BitMap for the icon}
  1559.     mBitMap       : BitMap;          {BitMap for the mask}
  1560.     MyILHndl:= iListHndl(GetResource('ICN#',iconID));          
  1561.     if MyILHndl = NIL then HandleError; 
  1562.         {and exit or whatever is appropriate}
  1563. Once we have a handle to the icons, we need to set up two bitMaps that we will be using later in CopyBits: 
  1564.         SetRect(icnRect,0,0,32,32);                { define the icon's 'bounds'}
  1565.     With iBitMap do Begin
  1566.          baseAddr:= @MyILHndl^^.icon;    
  1567.          rowbytes:= 4;                            { 4 * 8 =32}
  1568.          bounds:= icnRect;
  1569.      End; {with}
  1570.       With mBitMap do Begin
  1571.          baseAddr:= @MyILHndl^^.mask;
  1572.          rowbytes:= 4;
  1573.          bounds:= icnRect;
  1574.       End; {with}
  1575. Icons can represent desktop objects that are either selected or not. Folder and volume icons can either be open or not. The object (or the volume it is on) can either be online or offline. The Finder draws icons using all permutations of open, selected and online:
  1576. Drawing icons as non-open is basically the same for online and offline volumes. We need to punch a hole in the desktop for the icon. This is analogous to punching a hole in dough with an irregular shaped cookie-cutter. We can then sprinkle jimmies* all over the cookie and they will only stick in the area that we punched out (the mask). We do this by copyBitsing the mask onto the desktop (whatever pattern) to our destRect. For non-open, non-selected icons: 
  1577. we use the SrcBic mode so that we punch a white hole:
  1578.     SetRect(destRect,left,top,left+32,top+32);
  1579.     CopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL); 
  1580. Then we XOR in the icon:
  1581.      CopyBits(iBitMap,thePort^.portBits,icnRect,destRect,SrcXor,NIL);
  1582. That’s all there is to drawing an icon as non-open, non-selected. To draw the icon as non-open, selected:
  1583.          
  1584. we will OR in the mask, causing a mask-shaped BLACK hole to be punched in the desktop:
  1585.     CopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcOr,NIL); 
  1586. Then, as before, we XOR in the icon:
  1587.     CopyBits(iBitMap,thePort^.portBits,icnRect,destRect,SrcXOr,NIL);
  1588. To draw icons as non-opened for offline volumes:
  1589. we need to do a little more work. We need to XOR a ltGray pattern into the boundsRect of the icon. We will then punch the hole, draw the icon and then XOR out the ltgray pattern that does not fall inside the mask. So, to draw the icon as offline, non-open, non-selected we would:
  1590.     GetPenState(OldPen);        {save the pen state so we can restore it}
  1591.     PenMode(patXor);
  1592.       PenPat(ltGray);
  1593.       PaintRect(destRect);        {paint a ltGray background for icon}
  1594.       CopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL); {punch}
  1595.      PaintRect(destRect);{XOR out bits outside of the mask, leaving the mask} 
  1596.                 {filled with ltGray}
  1597.                                                 
  1598.                                            CopyBits(iBitMap,thePort^.portBits,icnRect,destRect,SrcOr,NIL);{ OR in }                                                                                   { the icon to the ltGray mask}
  1599. SetPenState(OldPen);                           {restore the old pen state}
  1600. To draw the icon as offline, non-open, selected:
  1601. we would use a similar approach:
  1602.         GetPenState(OldPen);        { save the pen state so we can restore it}
  1603.     PenMode(patXor);
  1604.     PenPat(dkGray);        { the icon is selected, so we need dkGray }
  1605.       PaintRect(destRect);        { paint a dkGray background for icon }
  1606.     {punch a hole in the background}
  1607.       CopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL);
  1608.     PaintRect(destRect);        {XOR out bits outside of the mask, leaving
  1609.                      the mask filled with dkGray}
  1610.     {BIC the icon to the dkGray mask}
  1611.     CopyBits(iBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL);
  1612.       SetPenState(OldPen);         {restore the old pen state}
  1613. Drawing the opened icons requires one less step. We don’’t have to CopyBits the icon in, we just use the mask. Online and offline icons are drawn the same way. To draw icons as open, selected:
  1614. we do the following:
  1615.         GetPenState(OldPen);        {save the pen state so we can restore it}
  1616.       PenMode(patXor);
  1617.       PenPat(dkGray);        { the icon is selected, so we need dkGray }
  1618.        PaintRect(destRect);        { paint a dkGray background for icon}
  1619.     {punch a hole in the background}
  1620.       CopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL);
  1621.   
  1622.       PaintRect(destRect);      {XOR out bits outside of the mask, leaving 
  1623.                     the mask filled with dkGray}
  1624.       SetPenState(OldPen);        {restore the old pen state}
  1625. To draw icons as open, non-selected:
  1626. we just need to change one line from above. Instead of XORing with a dkGray pattern, we use a ltGray pattern:
  1627.       PenPat(ltGray);        {icon is non-selected, so we need ltGray}
  1628. These techniques will work on any background, window-white or desktop-gray and all patterns in between. Have fun.
  1629. * jimmies : little bits of chocolate
  1630. Further Reference:
  1631. •    QuickDraw
  1632. •    Toolbox Utilities
  1633. Drawing Icons the System 7 Way
  1634. Imaging    M.IM.IconDrawing
  1635. Revised by:    Don Moccia and C.K. Haun <TR>    October 1992
  1636. Written by:    Jim Mensch and David Collins    October 1991
  1637. This Technical Note describes how to utilize the built-in System 7 icon drawing utility. Use this information to better conform to the System 7 visual human interface.
  1638. Changes since May 1992: In this Note, we replaced the C and Pascal interface files and corrected the related text. So much text was tweaked that change bars are used only on code changes. 
  1639. Introduction
  1640. With the introduction of System 7 for the Macintosh, Apple has defined a new look and feel for many screen elements that better utilize color. Among those redefined elements are the icons drawn by the Finder and other system components. Until now, Apple has not documented how to draw icons the way the Finder does in System 7.
  1641. This Technical Note discusses the icon toolkit calls that the Finder uses to draw and manipulate the screen icons. Two of the calls, PlotIconID and PlotCIconHandle, are the ones you will probably use the most since they simply deal with drawing single icons to the screen. Some parts of the toolbox require that an icon family handle be passed to them to allow the drawing of color icons. The icon toolkit provides calls that allow you to create, draw, and manipulate these handles.
  1642. The New 'ic' Type Resources
  1643. PlotIconID and PlotCIconHandle allow the use of standard CIcons as documented in Inside Macintosh Volume V. The PlotIconID call also permits the use of a new set of icon resources documented in Inside Macintosh Volume VI, Chapter 9. This new set is a collection of different icons, representing a single Finder object, into a family. Each member of the family has the same resource ID as the 'ICN#', and a resource type indicating the icon data it contains. Currently Apple has defined three sizes of icons and three bit depths for each size. The sizes are large (32 by 32 pixels), small (16 by 16 pixels), and mini (12 by 12 pixels). The bit depths are 1, 4, and 8. The actual resource types are defined as:
  1644. Large1BitMask    =    'ICN#';
  1645. Large4BitData    =    'icl4';
  1646. Large8BitData    =    'icl8';
  1647. Small1BitMask    =    'ics#';
  1648. Small4BitData    =    'ics4';
  1649. Small8BitData    =    'ics8';
  1650. Mini1BitMask     =    'icm#';
  1651. Mini4BitData     =    'icm4';
  1652. Mini8BitData     =    'icm8';
  1653. The 1-bit-per-pixel member of each size also contains the mask data for all icons of that size (yes, this means that all your icons of a certain size must have the same mask). A 1-bit-per-pixel member must exist for each icon size that PlotIconID uses. The icon size used is determined by the size of the destination rectangle. If the destination rectangle is greater than 16 pixels on a side then the large icon will be used. If the rectangle is 13–16 pixels on both sides, the small icon will be used. If it is 12 or less on each side, the mini-icon will be used. The bit depth is determined by the device of the grafPort you plot into at drawing time. Be sure to create a color grafPort when you want to use color icons.
  1654. Icon Families (or Suites and Caches As the Tool Set Refers to Them)
  1655. An icon family is simply a collection of icon handles that contain up to one image of each bit depth and size for a given icon. The family can be fully populated (every possible size or depth available), or it can have only those icons that exist or are needed. By using families, you remove the need to determine which size or depth of icon to use when drawing into a given rectangle. Several system routines, the Notification Manager for example, can take an icon family handle when an icon is requested. This permits them to use the proper color icons if available. In the case of a sparsely populated icon family, when the proper icon is not available, the icon toolkit will pick a substitute to produce the best results.
  1656. An icon cache is a family that also has a ProcPtr and a refCon. The main difference between a cache and a family is that the elements of the cache’s array are sparsely populated. When using an icon cache, the system either will use the entry in the icon family portion of the cache or, if the desired element is empty, it will call the procedure pointed to by the ProcPtr and request the data for the icon. The procedure should have this interface:
  1657. FUNCTION IconGetter(theType: ResType;
  1658.                     yourDataPtr: Ptr): Handle;
  1659. This function should return either the icon data to be drawn or NIL to signify that this entry in the icon cache does not exist. Icon caches can be used with all icon family calls. A few extra calls are also available to manipulate icon caches.
  1660. Drawing Modes or Transforms
  1661. In addition to various sizes and bit depths, icons can be drawn with different modes or transforms. Transforms are analogous to certain Finder states for the icons. For example, the transform that you would use to show an icon of a disk that has been ejected is ttOffline. Here is a list of the available transforms:
  1662. ttNone                =    $0;
  1663. ttDisabled            =    $1;
  1664. ttOffline             =    $2;
  1665. ttOpen                =    $3;
  1666. ttSelected            =    $4000;
  1667. ttSelectedDisabled    =    (ttSelected + ttDisabled);
  1668. ttSelectedOffline     =    (ttSelected + ttOffline);
  1669. ttSelectedOpen        =    (ttSelected + ttOpen);
  1670. The actual appearance of the icon drawn by each transform type may vary with future system software, so you should always use the transform that best fits the state it represents in your application. This way you will be consistent with future changes to the look and feel of regular system icons. Note the ttSelected transform can be added to any of the other transform types.
  1671. There are also transforms that use the Finder label colors to color the icon. To determine the proper label for a file’s icon, you can check bits 1–3 of the fdFlags field in the file’s Finder info. (See the Finder Interface chapter in Inside Macintosh Volume VI for more information). These bits contain a number from 0 to 7. Simply add the corresponding ttLabel value to the transform that you give the call. The label values are defined like this:
  1672. ttLabel1    =    $0100;
  1673. ttLabel2    =    $0200;
  1674. ttLabel3    =    $0300;
  1675. ttLabel4    =    $0400;
  1676. ttLabel5    =    $0500;
  1677. ttLabel6    =    $0600;
  1678. ttLabel7    =    $0700;
  1679. Alignment
  1680. Most icons do not fully fill their rectangle, and it is sometimes necessary to draw an icon relative to other data (like menu text). In these instances it is nice to be able to have the icon move in its rectangle so that it will be at a predictable location in the destination rectangle. When drawing an icon you can pass one of these standard alignments in the alignment parameter or you can add a vertical alignment to a horizontal alignment to create a composite alignment value.
  1681. atNone                =    $0;
  1682. atVerticalCenter      =    $1;
  1683. atTop                 =    $2;
  1684. atBottom              =    $3;
  1685. atHorizontalCenter    =    $4;
  1686. atAbsoluteCenter      =    (atVerticalCenter + atHorizontalCenter);
  1687. atCenterTop           =    (atTop + atHorizontalCenter);
  1688. atCenterBottom        =    (atBottom + atHorizontalCenter);
  1689. atLeft                =    $8;
  1690. atCenterLeft          =    (atVerticalCenter + atLeft);
  1691. atTopLeft             =    (atTop + atLeft);
  1692. atBottomLeft          =    (atBottom + atLeft);
  1693. atRight               =    $C;
  1694. atCenterRight         =    (atVerticalCenter + atRight);
  1695. atTopRight            =    (atTop + atRight);
  1696. atBottomRight         =    (atBottom + atRight);
  1697. And Now (Drum Roll Please) the Calls and What to Pass
  1698. Now that we have defined every major data type we can think of, here are the actual toolkit calls themselves. One word of caution: only the ForEachIconDo call protects the handle that is passed to it, so make your icon resources nonpurgeable.
  1699. Icon Family Calls
  1700. FUNCTION NewIconSuite(VAR theIconSuite: Handle): OSErr;
  1701. NewIconSuite returns an empty icon family handle with all members set to NIL.
  1702. FUNCTION AddIconToSuite(theIconData: Handle;
  1703.                         theSuite: Handle;
  1704.                         theType: ResType): OSErr;
  1705. This call will add the data in theIconData into the suite at the location reserved for theType of icon data. AddIconToSuite will replace any old data in that slot without disposing of it, so you may want to call GetIconFromSuite to obtain the old handle (if any) to dispose of it. This call will be used most often with the NewIconSuite call to fill the empty family after it’s created.
  1706. FUNCTION GetIconFromSuite(VAR theIconData: Handle;
  1707.                           theSuite: Handle;
  1708.                           theType: ResType): OSErr;
  1709. This call will return a handle to the pixel data of the family member of theSuite specified by theType. If you intend to dispose of this handle, be sure to call AddIconToSuite with a NIL handle to zero out the family entry.
  1710. FUNCTION ForEachIconDo(theSuite: Handle;
  1711.                        selector: IconSelectorValue;
  1712.                        action: IconAction;
  1713.                        yourDataPtr: Ptr): OSErr;
  1714. This routine will call your IconAction procedure (see below) for each icon in the family specified by selector and theSuite. The selector parameter is a bit-level flag that specifies which family members to operate on; they can be added together to create composite selectors that work on several different family members. The values for selector are:
  1715. svLarge1Bit        =    $00000001;
  1716. svLarge4Bit        =    $00000002;
  1717. svLarge8Bit        =    $00000004;
  1718. svSmall1Bit        =    $00000100;
  1719. svSmall4Bit        =    $00000200;
  1720. svSmall8Bit        =    $00000400;
  1721. svMini1Bit         =    $00010000;
  1722. svMini4Bit         =    $00020000;
  1723. svMini8Bit         =    $00040000;
  1724. svAllLargeData     =    $000000FF;
  1725. svAllSmallData     =    $0000FF00;
  1726. svAllMiniData      =    $00FF0000;
  1727. svAll1BitData      =    (svLarge1Bit + svSmall1Bit + svMini1Bit);
  1728. svAll4BitData      =    (svLarge4Bit + svSmall4Bit + svMini4Bit);
  1729. svAll8BitData      =    (svLarge8Bit + svSmall8Bit + svMini8Bit);
  1730. svAllAvailableD    =    $FFFFFFFF;
  1731. The action procedure that gets called for each icon type selected for the family is a Pascal type function with the following interface:
  1732. FUNCTION IconAction(theType: ResType;
  1733.                     VAR theIcon: Handle;
  1734.                     yourDataPtr: Ptr): OSErr;
  1735. The parameter theIcon is passed by reference here so that your routine can modify the contents of the suite directly. The yourDataPtr parameter is the value passed when you called ForEachIconDo. It allows you to easily communicate with your application. The action procedure returns an OSErr. If any value other than noErr is returned, ForEachIconDo will stop processing immediately and return the error passed. (Note: This implies that the icons selected may only be partially operated on. There is no guaranteed order in which the icons get operated on.)
  1736. FUNCTION GetIconSuite(VAR theIconSuite: Handle;
  1737.                       theResID: INTEGER;
  1738.                       selector: IconSelectorValue): OSErr;
  1739. GetIconSuite will create a new icon family and fill it from the current resource chain with the icons of resource ID theResID and types indicated by selector. This is the call you will probably use most often to create an icon family. Note that if you SetResLoad(False) before making this call, the suite will be filled with unloaded resource handles.
  1740. FUNCTION PlotIconSuite(theRect: Rect;
  1741.                        align: IconAlignmentType;
  1742.                        transform: IconTransformType;
  1743.                        theIconSuite: Handle): OSErr;
  1744. This call renders the proper icon image from the passed icon family based on the bit depth of 
  1745. the display you are using and the rectangle that you have passed. The parameters align and transform are applied to the icon selected for drawing and then the icon is plotted into the current grafPort. PlotIconSuite chooses the appropriate icon based primarily on size. Once the proper icon size is determined (based on the destination rectangle), the present member of that size with the deepest bit depth that the current device can use is selected. A size category is considered present if the black-and-white member (with mask), 'ICN#', 'ics#', or 'icm#', is present. PlotIconSuite can be used for both picture accumulation and printing.
  1746. FUNCTION DisposeIconSuite(theIconSuite: Handle;
  1747.                           disposeData: BOOLEAN): OSErr;
  1748. This call disposes the icon family handle itself. In addition, if disposeData is true, any of the icon data handles that do not belong to a resource fork will also be disposed.
  1749. FUNCTION SetSuiteLabel(theSuite: Handle; theLabel: INTEGER): OSErr;
  1750. This call allows you to specify a label to draw an icon of this suite when no label is specified in PlotIconSuite. This is used primarily to ensure that a family passed to a system routine gets drawn with the proper label. The default label can be overridden by specifying a label in PlotIconSuite.
  1751. FUNCTION GetSuiteLabel(theSuite: Handle): INTEGER;
  1752. GetSuiteLabel returns the label previously set with SetSuiteLabel.
  1753. Icon Cache Calls
  1754. In addition to the icon family calls, icon caches have these additional calls: 
  1755. FUNCTION MakeIconCache(VAR theHandle: Handle;
  1756.                        makeIcon: IconGetter;
  1757.                        yourDataPtr: UNIV Ptr): OSErr;
  1758. This call creates an empty icon cache similar to NewIconSuite, and associates the additional icon loading procedure and data value with the family.
  1759. FUNCTION LoadIconCache(theRect: Rect;
  1760.                        align: IconAlignmentType;
  1761.                        transform: IconTransformType;
  1762.                        theIconCache: Handle): OSErr;
  1763. This call allows preflight loading of certain elements of your icon cache. This is handy if you suspect that certain drawing operations may occur at a time not convenient for loading your icon data (e.g., when your resource fork might not be in open chain). LoadIconCache takes the same parameters as PlotIconSuite and uses the same criteria to select the icon to load. The grafPort must be set properly before making this call since it is one of the criteria for determining the icon to load.
  1764. The following four calls are provided to change theData or theProc associated with an icon cache:
  1765. FUNCTION GetIconCacheData(theCache: Handle; 
  1766.                           VAR theData: Ptr): OSErr;
  1767. FUNCTION SetIconCacheData(theCache: Handle; 
  1768.                           theData: Ptr): OSErr;
  1769. FUNCTION GetIconCacheProc(theCache: Handle; 
  1770.                           VAR theProc: IconGetter): OSErr;
  1771. FUNCTION SetIconCacheProc(theCache: Handle; 
  1772.                           theProc: IconGetter): OSErr;
  1773. Plotting Icons Not Part of a Suite
  1774. The next calls are grouped because they are similar. They let you plot an icon to the screen without your creating an icon suite. They are also good if you have a 'cicn' instead of an icon family.
  1775. FUNCTION PlotIconID(theRect: Rect;
  1776.                     align: IconAlignmentType;
  1777.                     transform: IconTransformType;
  1778.                     theResID: INTEGER): OSErr;
  1779. FUNCTION PlotCIconHandle(theRect: Rect;
  1780.                          align: IconAlignmentType;
  1781.                          transform: IconTransformType;
  1782.                          theCIcon: CIconHandle): OSErr;
  1783. FUNCTION PlotIconMethod(theRect: Rect;
  1784.                         align: IconAlignmentType;
  1785.                         transform: IconTransformType;
  1786.                         theMethod: IconGetter;
  1787.                         yourDataPtr: UNIV Ptr): OSErr;
  1788. FUNCTION PlotIconHandle(theRect: Rect;
  1789.                         align: IconAlignmentType;
  1790.                         transform: IconTransformType;
  1791.                         theIcon: Handle): OSErr;
  1792. FUNCTION PlotSICNHandle(theRect: Rect;
  1793.                         align: IconAlignmentType;
  1794.                         transform: IconTransformType;
  1795.                         theSICN: Handle): OSErr;
  1796. All these routines share the following parameters: theRect is the destination rectangle to draw the indicated icon into; align is the alignment method to use if the icon does not fit the rectangle given; transform indicates the desired appearance of the icon on the screen.
  1797. In PlotIconID, the parameter theResID is the resource ID of the family of 'ic' type resources to use. If the correct bit depth or the size required is not defined, the closest-fitting one will be used.
  1798. The PlotCIconHandle parameter theCIcon is a handle that you get to a standard QuickDraw color icon. Unlike PlotCIcon, PlotCIconHandle does not honor the current foreground and background colors. Call GetCIcon to load the icon. Dispose of it when you are done, since they can take up quite a bit of memory.
  1799. PlotIconMethod calls your IconGetter procedure, discussed earlier, to check for the existence of icon data. 
  1800. PlotIconHandle will plot the data from an 'ICN#' or 'ICON' resource from its handle. It is a new version of PlotIcon.
  1801. PlotSICNHandle plots the data of a 'SICN' resource from its handle. Only 'SICN' resources with a single member, or one in which the second member is a mask for the first, will plot correctly.
  1802. All the functions return an error code if things did not go well with the drawing or, in the case of the PlotIconID call, if the indicated icon family could not be used.
  1803. Miscellaneous Calls
  1804. FUNCTION GetLabel(labelNumber: INTEGER;
  1805.                   VAR labelColor: RGBColor;
  1806.                   VAR labelString: Str255): OSErr;
  1807. This call returns the actual color and string used in the label menu of the Finder and the label’s Control Panel. This information is provided in case you wish to include the label text or color when displaying a file’s icon in your application.
  1808. FUNCTION IconSuiteToRgn(theRgn: RgnHandle;
  1809.                         iconRect: Rect;
  1810.                         align: IconAlignmentType;
  1811.                         theIconSuite: Handle): OSErr;
  1812. FUNCTION IconIDToRgn(theRgn: RgnHandle;
  1813.                      iconRect: Rect;
  1814.                      align: IconAlignmentType;
  1815.                      iconID: INTEGER): OSErr;
  1816. FUNCTION IconMethodToRgn(theRgn: RgnHandle;
  1817.                          iconRect: Rect;
  1818.                          align: IconAlignmentType;
  1819.                          theMethod: IconGetter;
  1820.                          yourDataPtr: Ptr): OSErr;
  1821. These routines will create a region from the mask of the icon selected by the iconRect and align values passed. They will allow you to do accurate hit testing and outline dragging of an icon in your application. The RgnHandle must have been previously allocated before you make this call.
  1822. FUNCTION RectInIconSuite(testRect: Rect;
  1823.                          iconRect: Rect;
  1824.                          align: IconAlignmentType;
  1825.                          theIconSuite: Handle): BOOLEAN;
  1826. FUNCTION RectInIconID(testRect: Rect;
  1827.                       iconRect: Rect;
  1828.                       align: IconAlignmentType;
  1829.                       iconID: INTEGER): BOOLEAN;
  1830. FUNCTION RectInIconMethod(testRect: Rect;
  1831.                           iconRect: Rect;
  1832.                           align: IconAlignmentType;
  1833.                           theMethod: IconGetter;
  1834.                           yourDataPtr: Ptr): BOOLEAN;
  1835. FUNCTION PtInIconSuite(testPt: Point;
  1836.                        iconRect: Rect;
  1837.                        align: IconAlignmentType;
  1838.                        theIconSuite: Handle): BOOLEAN;
  1839. FUNCTION PtInIconID(testPt: Point;
  1840.                     iconRect: Rect;
  1841.                     align: IconAlignmentType;
  1842.                     iconID: INTEGER): BOOLEAN;
  1843. FUNCTION PtInIconMethod(testPt: Point;
  1844.                         iconRect: Rect;
  1845.                         align: IconAlignmentType;
  1846.                         theMethod: IconGetter;
  1847.                         yourDataPtr: Ptr): BOOLEAN;
  1848. These calls hit test the passed Point or Rect against the icon indicated. The parameters iconRect and align, and the grafPort should be the same as when the icon was last drawn. The functions return true if the point is in the icon mask or if the rectangle intersects the icon mask.
  1849. Error Codes
  1850. The Icon Utilities will pass back any errors encountered during execution, so you can expect to see Memory Manager, Resource Manager, and other normal errors.
  1851. There is one error code defined specifically for the Icon Utilities routines that may be returned by the Icon plotting routines.
  1852. { Pascal }
  1853. CONST
  1854.     noMaskFound = -1000;
  1855. END;
  1856. /* C */
  1857. #define noMaskFound    -1000
  1858. This error will be returned if the Icon Utilities package could not find or create a mask for the icon family.  The Icon Utilities will use the correct mask for each icon size, if one is available.  If no mask for a specific size is available, a mask will be created from any mask in the family, but if there are no 1 bit images and no mask in the family, plotting calls will fail with this error.
  1859. Type(def)s and Glue for Pascal and C
  1860. The Pascal and C interfaces are provided here to copy and paste since the current MPW standard interface files do not contain the glue for these calls. Electronic versions of this note are on AppleLink (Developer Support: Developer Services: Technical Documentation: Macintosh Technical Notes: Imaging: Graphics: Icon Drawing in 7.sit (Stuffit)) and the Developer CD (Technical Documentation: Macintosh Technical Notes: Imaging: Graphics: Icon Drawing in 7).
  1861. MPW C, Pascal, and Assembler files also have been submitted to AppleLink and the Developer CD, but their paths were not known when this note was written.
  1862. { Pascal Types }
  1863. IconAction         =  ProcPtr;  {FUNCTION IconAction(theType: ResType;
  1864.                                                      VAR theIcon: Handle;
  1865.                                                      yourDataPtr: Ptr): OSErr;}
  1866. IconGetter         =  ProcPtr;  {FUNCTION IconGetter(theType: ResType;
  1867.                                                      yourDataPtr: Ptr): Handle;}
  1868. IconSelectorValue  =  LONGINT;
  1869. IconAlignmentType  =  INTEGER;
  1870. IconTransformType  =  INTEGER;
  1871. { Pascal Glue }
  1872. FUNCTION PlotIconID(theRect: Rect; align: IconAlignmentType; transform: IconTransformType;
  1873.                     theResID: INTEGER): OSErr;
  1874.          INLINE  $303C, $0500, $ABC9;
  1875. FUNCTION NewIconSuite(VAR theIconSuite: Handle): OSErr;
  1876.          INLINE  $303C, $0207, $ABC9;
  1877. FUNCTION AddIconToSuite(theIconData: Handle; theSuite: Handle; theType: ResType): OSErr;
  1878.          INLINE  $303C, $0608, $ABC9;
  1879. FUNCTION GetIconFromSuite(VAR theIconData: Handle; theSuite: Handle; theType: ResType): OSErr;
  1880.          INLINE  $303C, $0609, $ABC9;
  1881. FUNCTION ForEachIconDo(theSuite: Handle; selector: IconSelectorValue; action: IconAction;
  1882.                        yourDataPtr: Ptr): OSErr;
  1883.          INLINE  $303C, $060A, $ABC9;
  1884. FUNCTION GetIconSuite(VAR theIconSuite: Handle; theResID: INTEGER;
  1885.                       selector: IconSelectorValue): OSErr;
  1886.          INLINE  $303C, $0501, $ABC9;
  1887. FUNCTION DisposeIconSuite(theIconSuite: Handle; disposeData: BOOLEAN): OSErr;
  1888.          INLINE  $303C, $0302, $ABC9;
  1889. FUNCTION PlotIconSuite(theRect: Rect; align: IconAlignmentType; transform: IconTransformType;
  1890.                        theIconSuite: Handle): OSErr;
  1891.         INLINE  $303C, $0603, $ABC9;
  1892. FUNCTION MakeIconCache(VAR theHandle: Handle; makeIcon: IconGetter;
  1893.                        yourDataPtr: UNIV Ptr): OSErr;
  1894.          INLINE  $303C, $0604, $ABC9;
  1895. FUNCTION LoadIconCache(theRect: Rect; align: IconAlignmentType; transform: IconTransformType;
  1896.                        theIconCache: Handle): OSErr;
  1897.          INLINE  $303C, $0606, $ABC9;
  1898. FUNCTION PlotIconMethod(theRect: Rect; align: IconAlignmentType;
  1899.                         transform: IconTransformType; theMethod: IconGetter;
  1900.                         yourDataPtr: UNIV Ptr): OSErr; 
  1901.          INLINE  $303C, $0805, $ABC9;
  1902. FUNCTION GetLabel(labelNumber: INTEGER; VAR labelColor: RGBColor;
  1903.                   VAR labelString: Str255): OSErr;
  1904.          INLINE  $303C, $050B, $ABC9;
  1905. FUNCTION PtInIconID(testPt: Point; iconRect: Rect; align: IconAlignmentType;
  1906.                     iconID: INTEGER): BOOLEAN;
  1907.          INLINE  $303C, $060D, $ABC9;
  1908. FUNCTION PtInIconSuite(testPt: Point; iconRect: Rect; align: IconAlignmentType;
  1909.                        theIconSuite: Handle): BOOLEAN;
  1910.          INLINE  $303C, $070E, $ABC9;
  1911. FUNCTION PtInIconMethod(testPt: Point; iconRect: Rect; align: IconAlignmentType;
  1912.                         theMethod: IconGetter; yourDataPtr: Ptr): BOOLEAN;
  1913.          INLINE  $303C, $090F, $ABC9;
  1914. FUNCTION RectInIconID(testRect: Rect; iconRect: Rect; align: IconAlignmentType;
  1915.                       iconID: INTEGER): BOOLEAN;
  1916.          INLINE  $303C, $0610, $ABC9;
  1917. FUNCTION RectInIconSuite(testRect: Rect; iconRect: Rect; align: IconAlignmentType;
  1918.                          theIconSuite: Handle): BOOLEAN;
  1919.          INLINE  $303C, $0711, $ABC9;
  1920. FUNCTION RectInIconMethod(testRect: Rect; iconRect: Rect; align: IconAlignmentType;
  1921.                           theMethod: IconGetter; yourDataPtr: Ptr): BOOLEAN;
  1922.          INLINE  $303C, $0912, $ABC9;
  1923. FUNCTION IconIDToRgn(theRgn: RgnHandle; iconRect: Rect; align: IconAlignmentType;
  1924.                      iconID: INTEGER): OSErr;
  1925.          INLINE  $303C, $0913, $ABC9;
  1926. FUNCTION IconSuiteToRgn(theRgn: RgnHandle; iconRect: Rect; align: IconAlignmentType;
  1927.                         theIconSuite: Handle): OSErr;
  1928.          INLINE  $303C, $0914, $ABC9;
  1929. FUNCTION IconMethodToRgn(theRgn: RgnHandle; iconRect: Rect; align: IconAlignmentType;
  1930.                          theMethod: IconGetter; yourDataPtr: Ptr): OSErr;
  1931.          INLINE  $303C, $0915, $ABC9;
  1932. FUNCTION SetSuiteLabel(theSuite: Handle; theLabel: INTEGER): OSErr;
  1933.          INLINE  $303C, $0316, $ABC9;
  1934. FUNCTION GetSuiteLabel(theSuite: Handle): INTEGER;
  1935.          INLINE  $303C, $0217, $ABC9;
  1936. FUNCTION GetIconCacheData(theCache: Handle; VAR theData: Ptr): OSErr;
  1937.          INLINE  $303C, $0419, $ABC9;
  1938. FUNCTION SetIconCacheData(theCache: Handle; theData: Ptr): OSErr;
  1939.          INLINE  $303C, $041A, $ABC9;
  1940. FUNCTION GetIconCacheProc(theCache: Handle; VAR theProc: IconGetter): OSErr;
  1941.          INLINE  $303C, $041B, $ABC9;
  1942. FUNCTION SetIconCacheProc(theCache: Handle; theProc: IconGetter): OSErr;
  1943.          INLINE  $303C, $041C, $ABC9;
  1944. FUNCTION PlotIconHandle(theRect: Rect; align: IconAlignmentType;
  1945.                         transform: IconTransformType; theIcon: Handle): OSErr;
  1946.          INLINE  $303C, $061D, $ABC9;
  1947. FUNCTION PlotSICNHandle(theRect: Rect; align: IconAlignmentType;
  1948.                         transform: IconTransformType; theSICN: Handle): OSErr;
  1949.          INLINE  $303C, $061E, $ABC9;
  1950. FUNCTION PlotCIconHandle(theRect: Rect; align: IconAlignmentType;
  1951.                          transform: IconTransformType; theCIcon: CIconHandle): OSErr;
  1952.          INLINE  $303C, $061F, $ABC9;
  1953. /* C Typedefs */
  1954. typedef pascal OSErr   (*IconAction)(ResType theType, Handle *theIcon, void *yourDataPtr);
  1955. typedef pascal Handle  (*IconGetter)(ResType theType, void *yourDataPtr);
  1956. typedef unsigned long  IconSelectorValue;
  1957. typedef short          IconAlignmentType;
  1958. typedef short          IconTransformType;
  1959. /* C Glue */
  1960. pascal OSErr PlotIconID(const Rect *theRect, IconAlignmentType align,
  1961.                         IconTransformType transform, short theResID)
  1962.        =  {0x303C, 0x0500, 0xABC9};
  1963. pascal OSErr NewIconSuite(Handle *theIconSuite)
  1964.        =  {0x303C, 0x0207, 0xABC9};
  1965. pascal OSErr AddIconToSuite(Handle theIconData, Handle theSuite, ResType theType)
  1966.        =  {0x303C, 0x0608, 0xABC9};
  1967. pascal OSErr GetIconFromSuite(Handle *theIconData, Handle theSuite, ResType theType)
  1968.        =  {0x303C, 0x0609, 0xABC9};
  1969. pascal OSErr ForEachIconDo(Handle theSuite, IconSelectorValue selector, IconAction action,
  1970.                            void *yourDataPtr)
  1971.        =  {0x303C, 0x080A, 0xABC9};
  1972. pascal OSErr GetIconSuite(Handle *theIconSuite, short theResID, IconSelectorValue selector)
  1973.        =  {0x303C, 0x0501, 0xABC9};
  1974. pascal OSErr DisposeIconSuite(Handle theIconSuite, Boolean disposeData)
  1975.        =  {0x303C, 0x0302, 0xABC9};
  1976. pascal OSErr PlotIconSuite(const Rect *theRect, IconAlignmentType align,
  1977.                            IconTransformType transform, Handle theIconSuite)
  1978.        =  {0x303C, 0x0603, 0xABC9};
  1979. pascal OSErr MakeIconCache(Handle *theHandle, IconGetter makeIcon, void *yourDataPtr)
  1980.        =  {0x303C, 0x0604, 0xABC9};
  1981. pascal OSErr LoadIconCache(const Rect *theRect, IconAlignmentType align,
  1982.                            IconTransformType transform, Handle theIconCache)
  1983.        =  {0x303C, 0x0606, 0xABC9};
  1984. pascal OSErr PlotIconMethod(const Rect *theRect, IconAlignmentType align,
  1985.                             IconTransformType transform, IconGetter theMethod,
  1986.                             void *yourDataPtr)
  1987.        =  {0x303C, 0x0805, 0xABC9};
  1988. pascal OSErr GetLabel(short labelNumber, RGBColor *labelColor, Str255 labelString)
  1989.        =  {0x303c, 0x050B, 0xABC9};
  1990. pascal Boolean PtInIconID(Point testPt, Rect *iconRect, IconAlignmentType alignment,
  1991.                           short iconID)
  1992.        =  {0x303c, 0x060D, 0xABC9};
  1993. pascal Boolean PtInIconSuite(Point testPt, Rect *iconRect, IconAlignmentType alignment,
  1994.                              Handle theIconSuite)
  1995.        =  {0x303c, 0x070E, 0xABC9};
  1996. pascal Boolean PtInIconMethod(Point testPt, Rect *iconRect, IconAlignmentType alignment,
  1997.                               IconGetter theMethod, void *yourDataPtr)
  1998.        =  {0x303c, 0x090F, 0xABC9};
  1999. pascal Boolean RectInIconID(Rect *testRect, Rect *iconRect, IconAlignmentType alignment,
  2000.                             short iconID)
  2001.        =  {0x303c, 0x0610, 0xABC9};
  2002. pascal Boolean RectInIconSuite(Rect *testRect, Rect *iconRect, IconAlignmentType alignment,
  2003.                                Handle theIconSuite)
  2004.        =  {0x303c, 0x0711, 0xABC9};
  2005. pascal Boolean RectInIconMethod(Rect *testRect, Rect *iconRect, IconAlignmentType alignment,
  2006.                                 IconGetter theMethod, void *yourDataPtr)
  2007.        =  {0x303c, 0x0912, 0xABC9};
  2008. pascal OSErr IconIDToRgn(RgnHandle theRgn, Rect *iconRect, IconAlignmentType alignment,
  2009.                          short iconID)
  2010.        =  {0x303c, 0x0613, 0xABC9};
  2011. pascal OSErr IconSuiteToRgn(RgnHandle theRgn, Rect *iconRect, IconAlignmentType alignment,
  2012.                             Handle theIconSuite)
  2013.        =  {0x303c, 0x0714, 0xABC9};
  2014. pascal OSErr IconMethodToRgn(RgnHandle theRgn, Rect *iconRect, IconAlignmentType alignment,
  2015.                              IconGetter theMethod, void *yourDataPtr)
  2016.        =  {0x303c, 0x0915, 0xABC9};
  2017. pascal OSErr SetSuiteLabel(Handle theSuite, short theLabel)
  2018.        =  {0x303C, 0x0316, 0xABC9};
  2019. pascal short GetSuiteLabel(Handle theSuite)
  2020.        =  {0x303C, 0x0217, 0xABC9};
  2021. pascal OSErr GetIconCacheData(Handle theCache, void **theData)
  2022.        =  {0x303C, 0x0419, 0xABC9};
  2023. pascal OSErr SetIconCacheData(Handle theCache, void *theData)
  2024.        =  {0x303C, 0x041A, 0xABC9};
  2025. pascal OSErr GetIconCacheProc(Handle theCache, IconGetter *theProc)
  2026.        =  {0x303C, 0x041B, 0xABC9};
  2027. pascal OSErr SetIconCacheProc(Handle theCache, IconGetter theProc)
  2028.        =  {0x303C, 0x041C, 0xABC9};
  2029. pascal OSErr PlotIconHandle(const Rect *theRect, IconAlignmentType align,
  2030.                             IconTransformType transform, Handle theIcon)
  2031.        =  {0x303C, 0x061D, 0xABC9};
  2032. pascal OSErr PlotSICNHandle(const Rect *theRect, IconAlignmentType align,
  2033.                             IconTransformType transform, Handle theSICN)
  2034.        =  {0x303C, 0x061E, 0xABC9};
  2035. pascal OSErr PlotCIconHandle(const Rect *theRect, IconAlignmentType align,
  2036.                              IconTransformType transform, CIconHandle theCIcon)
  2037.        =  {0x303C, 0x061F, 0xABC9};
  2038. Further Reference:
  2039. •    Inside Macintosh, Volume V, QuickDraw chapter
  2040. •    Inside Macintosh, Volume VI, Finder Interface chapter
  2041. Displaying Large PICT Files 
  2042. Imaging    M.IM.LargePict
  2043. Revised by:        March 1988
  2044. Written by:    Rick Blair     July 1987
  2045. Now that we have scanners and other massive-picture producing types of applications, there is a need to address the problem of how to display a PICT format object that is bigger than a current PICT resource is allowed to be. Note that this technique applies equally well to version 1 and version 2 (word-opcode) pictures as produced by the Macintosh II.
  2046. Future Compatibility
  2047. Think of the handle returned by a GetResource('PICT',ID) as a “handle” in the more general sense of being an abstract “tag”—something that the ROM routines can use to draw the picture with. Don’t assume that the entire picture has been read into memory or that you can directly read any bytes beyond the basic Picture record structure (picSize followed by picFrame). Someday we may provide a mechanism for the resource to be disk- instead of memory-based. The QuickDraw bottleneck procedures will know how to get data from and put data into the pictures in any case.
  2048. Spooling from a PICT file
  2049. In order to display pictures of arbitrary size, your application should be able to import a QuickDraw picture from a file of type PICT. This is the file produced by a “Save as…” from MacDraw with the PICT option selected.
  2050. What follows is a small program fragment that demonstrates how to spool in a picture from [the data fork of] a PICT file. The picture can be larger than the historical 32K resource size. See technical note #88 if you are unfamiliar with the Signal mechanism. We assume that a CatchSignals has been done before GetandDrawPICTFile is called.
  2051. MPW Pascal Example
  2052.     {the following variable must be at the top level}
  2053.     VAR
  2054.        globalRef   : INTEGER;      {refNum of the file to read from}
  2055.     {the following procedure must be at the top level}
  2056.     PROCEDURE GetPICTData(dataPtr: Ptr; byteCount: INTEGER);
  2057.     {replacement for the QuickDraw bottleneck routine}
  2058.        VAR
  2059.           err         : OSErr;
  2060.           longCount   : LONGINT;
  2061.        BEGIN
  2062.           longCount := byteCount;
  2063.           err := FSRead(globalRef,longCount,dataPtr);
  2064.           {can't check for an error because we don't know how to handle it}
  2065.        END;
  2066.     CONST
  2067.        abortPICT    = 128;         {error code if DrawPicture aborted}
  2068.     PROCEDURE GetDrawPICTFile;     {read in a PICT FILE selected by the user}
  2069.        VAR
  2070.           wher        : Point;     {where to display dialog}
  2071.           reply       : SFReply;   {reply record}
  2072.           myFileTypes : SFTypeList; {more Standard FILE goodies}
  2073.           numFileTypes: INTEGER;
  2074.           savedProcs  : QDProcsPtr;
  2075.           myProcs     : QDProcs;   {use CQDProcs for a color window}
  2076.           myPicture   : PicHandle; {we need a picture handle for DrawPicture}
  2077.           longCount   : LONGINT;
  2078.           myEOF       : LONGINT;
  2079.           myFilePos   : LONGINT;
  2080.        BEGIN
  2081.           wher.h := 20;
  2082.           wher.v := 20;
  2083.           numFileTypes := 1;       {display PICT files}
  2084.           myFileTypes[0] := 'PICT';
  2085.           SFGetFile(wher,'',NIL,numFileTypes,myFileTypes,NIL,reply);
  2086.           IF reply.good THEN BEGIN
  2087.              SetStdProcs(myProcs); {use SetStdCProcs for a CGrafPort}
  2088.              myProcs.getPicProc := @GetPICTData;
  2089.              savedProcs := thePort^.grafProcs; {set the grafProcs to ours}
  2090.              thePort^.grafProcs := @myProcs;
  2091.              myPicture := PicHandle(NewHandle(SizeOf(myPicture)));
  2092.              Signal(FSOpen(reply.fname,reply.vRefNum,globalRef));
  2093.              Signal(GetEOF(globalRef,myEOF)); {get EOF for later check}
  2094.              Signal(SetFPos(globalRef,fsFromStart,512)); {skip header}
  2095.              {read in the (obsolete) size word and the picFrame}
  2096.              longCount := SizeOf(myPicture);
  2097.              Signal(FSRead(globalRef,longCount,Ptr(myPicture^)));
  2098.              DrawPicture(myPicture,myPicture^^.picFrame); {draw the picture}
  2099.              Signal(GetFPos(globalRef,filePos)); {get position for check}
  2100.              Signal(FSClose(globalRef));
  2101.              DisposHandle(Handle(myPicture));
  2102.              thePort^.grafProcs := savedProcs; {restore the procs}
  2103.              {Check for errors. If there wasn't enough room,}
  2104.              {DrawPicture will abort; the FILE position mark}
  2105.              {won't be at the end of the FILE.}
  2106.              IF filePos <> myEOF THEN Signal(abortPICT);
  2107.           END; {IF reply.good}
  2108.        END; {GetDrawPICTFile}
  2109. MPW C Example
  2110. /*replacement for the QuickDraw bottleneck routine*/
  2111. pascal void GetPICTData(dataPtr,byteCount)
  2112. Ptr            dataPtr; 
  2113. short            byteCount;
  2114. { /* GetPICTData */
  2115.     OSErr            err;
  2116.     long            longCount;
  2117.     longCount = byteCount;
  2118.     err = FSRead(globalRef,&longCount,dataPtr);
  2119.     /*can't check for an error because we don't know how to handle it*/
  2120. } /* GetPICTData */
  2121. /*error code if DrawPicture aborted*/
  2122. #define       abortPICT     128         
  2123. OSErr GetDrawPICTFile()        /*read in a PICT FILE selected by the user*/
  2124. {    /* GetDrawPICTFile */   
  2125.     Point         wher;         /*where to display dialog*/
  2126.     SFReply    reply;      /*reply record*/
  2127.     SFTypeList    myFileTypes;    /*more Standard FILE goodies*/
  2128.     short         numFileTypes;
  2129.     OSErr        err;
  2130.     QDProcsPtr    savedProcs;
  2131.     QDProcs    myProcs;    /*use CQDProcs for a color window*/
  2132.     PicHandle    myPicture;    /*we need a picture handle for DrawPicture*/
  2133.     long        longCount,myEOF,filePos;
  2134.           wher.h = 20;
  2135.           wher.v = 20;
  2136.           numFileTypes = 1;                   /*display PICT files*/
  2137.           myFileTypes[0] = 'PICT';
  2138.           SFGetFile(wher,'',nil,numFileTypes,myFileTypes,nil,&reply);
  2139.           if (reply.good)  
  2140.         {
  2141.             SetStdProcs(&myProcs);
  2142.             /*use SetStdCProcs for a CGrafPort*/
  2143.                  myProcs.getPicProc = GetPICTData;
  2144.                  savedProcs = (*qd.thePort).grafProcs;
  2145.             /*set the grafProcs to ours*/
  2146.                  (*qd.thePort).grafProcs = &myProcs;
  2147.                  myPicture = (PicHandle)NewHandle(sizeof(Picture));
  2148.             err = FSOpen(&reply.fName,reply.vRefNum,&globalRef);
  2149.             if (err != noErr) return err;
  2150.                   err = GetEOF(globalRef,&myEOF);
  2151.             /*get EOF for later check*/
  2152.             if (err != noErr) return err;
  2153.             err = SetFPos(globalRef,fsFromStart,512);/*skip header*/
  2154.                  if (err != noErr) return err;
  2155.                  /*read in the (obsolete) size word and the picFrame*/
  2156.                  longCount = sizeof(Picture);
  2157.                  err = FSRead(globalRef,&longCount,(Ptr)*myPicture);
  2158.                  if (err != noErr) return err;
  2159.                  DrawPicture(myPicture,&(**myPicture).picFrame); /*draw                                 the picture*/
  2160.             err = GetFPos(globalRef,&filePos);/*get position for                                 check*/
  2161.                  if (err != noErr) return err;
  2162.                  err = FSClose(globalRef);
  2163.                  if (err != noErr) return err;
  2164.                  DisposHandle((Handle)myPicture);
  2165.                  (*qd.thePort).grafProcs = savedProcs;/*restore the                                 procs*/
  2166.                  /*Check for errors. if there wasn't enough room,*/
  2167.                  /*DrawPicture will abort; the FILE position mark*/
  2168.                  /*won't be at the end of the FILE.*/
  2169.             if (filePos != myEOF)  return abortPICT;
  2170.             else return noErr;
  2171.           } /*if (reply.good) */
  2172. }     /* GetDrawPICTFile */
  2173. More on Picture Compatibility
  2174. Many applications already support PICT resources larger than 32K. The 128K ROMs (and later) allow pictures as large as memory (or spooling) will accommodate. This was made possible by having QuickDraw ignore the size word and simply read the picture until the end-of-picture opcode was reached.
  2175. For maximum safety and convenience, let QuickDraw generate and interpret your pictures.
  2176. While Apple has provided you with the data formats that allow you to read or write picture data directly, we recommend that you always let DrawPicture or OpenPicture and ClosePicture process the opcodes.
  2177. One reason to read a picture directly by scanning the opcodes would be to disassemble it to, for example, extract a Color QuickDraw pixel map to save off in a private data structure. This shouldn’t normally be necessary.
  2178. If you do look at the picture data be sure and check the version information. You may want to put up an alert in your application that indicates to the user when a picture was created using a later version of the picture format than your application recognizes, letting them know that some elements of the picture cannot be displayed. If the version information indicates a QuickDraw picture version later than the one recognized by your application, your program should skip over the new opcodes and only attempt to parse the ones it knows.
  2179. As with reading picture data directly, it is best to use QuickDraw to create data in the PICT format. If you do need to create PICT format data directly, it is essential that you use the latest opcode specifications and that you thoroughly test the data produced on both color and black and white Macintosh machines. Contact Macintosh Developer Technical Support if you are not sure that you have the latest specifications.
  2180. Apple does not guarantee that a picture which wasn’t produced by QuickDraw will work.
  2181. Further Reference:
  2182. •    QuickDraw
  2183. •    Technical Note M.IM.PictureOpcodes —
  2184.         Internal Picture Format
  2185. •    Technical Note M.PT.Signals —
  2186.         Signals
  2187. LaserWriter Utility Q&As
  2188. Imaging    M.IM.LWUtil.Q&As
  2189. Revised by:    Developer Support Center    October 1992
  2190. Written by:    Developer Support Center    October 1990
  2191. This Technical Note contains a collection of Q&As relating to a specific topic—questions you’ve sent the Developer Support Center (DSC) along with answers from the DSC engineers. While DSC engineers have checked the Q&A content for accuracy, the Q&A Technical Notes don’t have the editing and organization of other Technical Notes. The Q&A function is to get new technical information and updates to you quickly, saving the polish for when the information migrates into reference manuals.
  2192. Q&As are now included with Technical Notes to make access to technical updates easier for you. If you have comments or suggestions about Q&A content or distribution, please let us know by sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical questions about Q&A content to DEVSUPPORT for resolution.
  2193. New Q&As and Q&As revised this month are marked with a bar in the side margin.
  2194. SCSI drive format for LaserWriter II NTX with Rev. 3 ROMs
  2195. Written:    5/3/91
  2196. Last reviewed:    6/26/91
  2197. What could be causing intermittent PostScript errors from a LaserWriter II NTX with an SCSI hard disk mounted after installing the Rev 3 ROM upgrade?
  2198. ___
  2199. The LaserWriter II NTX with Rev 3 ROMs does not work properly with a hard disk formatted with the LaserWriter Font Utility 1.x. You need to reformat the disk and copy the fonts back onto the hard disk using the LaserWriter Font Utility 2.0.2. Unfortunately, there is no way to make this procedure easier.
  2200. LaserWriter Font Utility copies Postscript file to printer
  2201. Written:    9/23/91
  2202. Last reviewed:    10/8/91
  2203. Is there a utility that will send a PostScript file from disk to the LaserWriter?
  2204. ___
  2205. The LaserWriter Font Utility handles this job and is part of the System 7 disk set. On the System 7 Golden Master CD, the path is System 7.0: System Software 7.0: Installer Version: Tidbits folder.
  2206. Drawing Into an Off-Screen Bitmap
  2207. Imaging    M.IM.OffscreenBitMap
  2208. Revised by:    Jon Zap & Forrest Tanaka    June 1990
  2209. Written by:    Jim Friedlander & Ginger Jernigan    July 1985
  2210. This Technical Note provides an example of creating an off-screen bitmap, drawing to it, and then copying from it to the screen.
  2211. Changes since April 1990:  Clarified the section on window updates with off-screen bitmaps to explicitly limit these updates to your own windows.
  2212. The following is an example of creating and drawing to an off-screen bitmap, then copying from it to an on-screen window.  We supply this example in both MPW Pascal and C.
  2213. MPW Pascal
  2214. First, let’s look at a general purpose function to create an off-screen bitmap.  This function creates the GrafPort on the heap.  You could also create it on the stack and pass the uninitialized structure to a function similar to this one.
  2215. FUNCTION CreateOffscreenBitMap(VAR newOffscreen:GrafPtr; inBounds:Rect) : BOOLEAN;
  2216. VAR
  2217.   savePort  : GrafPtr;
  2218.   newPort   : GrafPtr;
  2219. BEGIN
  2220.   GetPort(savePort);        {need this to restore thePort after OpenPort changes it}
  2221.   newPort := GrafPtr(NewPtr(sizeof(GrafPort)));    {allocate the GrafPort}
  2222.   IF MemError <> noErr THEN BEGIN
  2223.     CreateOffscreenBitMap := false;                {failed to allocate it}
  2224.     EXIT(CreateOffscreenBitMap);
  2225.   END;
  2226.   {
  2227.   the OpenPort call does the following . . . 
  2228.     allocates space for visRgn (set to screenBits.bounds) and clipRgn (set wide open)
  2229.     sets portBits to screenBits
  2230.     sets portRect to screenBits.bounds
  2231.     etc. (see IM I-163,164)
  2232.     side effect: does a SetPort(offScreen)
  2233.   }
  2234.   OpenPort(newPort);
  2235.   {make bitmap exactly the size of the bounds that caller supplied}
  2236.   WITH newPort^ DO BEGIN {portRect, clipRgn, and visRgn are in newPort}
  2237.     portRect := inBounds;
  2238.     RectRgn(clipRgn, inBounds);        {avoid wide-open clipRgn, to be safe}
  2239.     RectRgn(visRgn, inBounds);         {in case inBounds is > screen bounds}
  2240.   END;
  2241.   WITH newPort^.portBits DO BEGIN       {baseAddr, rowBytes and bounds are in newPort}
  2242.     bounds := inBounds;
  2243.     {rowBytes is size of row  It must be rounded up to even number of bytes}
  2244.     rowBytes := ((inBounds.right - inBounds.left + 15) DIV 16) * 2;
  2245.     {number of bytes in BitMap is rowBytes * number of rows}
  2246.     {see note at end of Technical Note about using _NewHandle rather than _NewPtr}
  2247.     baseAddr := NewPtr(rowBytes * LONGINT(inBounds.bottom - inBounds.top));
  2248.   END;
  2249.   IF MemError <> noErr THEN BEGIN    {see if we had enough room for the bits}
  2250.     SetPort(savePort);
  2251.     ClosePort(newPort);              { dump the visRgn and clipRgn }
  2252.     DisposPtr(Ptr(newPort));         { dump the GrafPort}
  2253.     CreateOffscreenBitMap := false;
  2254.   END
  2255.   ELSE BEGIN
  2256.     { since the bits are just memory, let's erase them before we start }
  2257.     EraseRect(inBounds);            {OpenPort did a SetPort(newPort)}
  2258.     newOffscreen := newPort;
  2259.     SetPort(savePort);
  2260.     CreateOffscreenBitMap := true;
  2261.   END;
  2262. END;
  2263. Here is the procedure to get rid of an off-screen bitmap created by the previous function:
  2264. PROCEDURE DestroyOffscreenBitMap(oldOffscreen : GrafPtr);
  2265. BEGIN
  2266.   ClosePort(oldOffscreen);                       { dump the visRgn and clipRgn }
  2267.   DisposPtr(oldOffscreen^.portBits.baseAddr);    { dump the bits }
  2268.   DisposPtr(Ptr(oldOffscreen));                  { dump the port }
  2269. END;
  2270. Now that you know how to create and destroy an off-screen bitmap, let’s go through the motions of using one.  First, let’s define a few things to make the _NewWindow call a little clearer.
  2271. CONST
  2272.   kIsVisible   = true;
  2273.   kNoGoAway    = false;
  2274.   kMakeFrontWindow = -1;
  2275.   myString     = 'The EYE';  {string to display}
  2276. Here’s the body of the test code:
  2277. VAR
  2278.   offscreen : GrafPtr;    {our off-screen bitmap}
  2279.   ovalRect  : Rect;       {used for example drawing}
  2280.   myWBounds : Rect;       {for creating window}
  2281.   OSRect    : Rect;       {portRect and bounds for off-screen bitmap}
  2282.   myWindow  : WindowPtr;
  2283. BEGIN
  2284.   InitToolbox;                       {exercise left to the reader}
  2285.   myWBounds := screenBits.bounds;    { size of main screen }
  2286.   InsetRect(myWBounds, 50,50);       { make it fit better }
  2287.   myWindow := NewWindow(NIL, myWBounds, 'Test Window', kIsVisible,
  2288.                         noGrowDocProc, WindowPtr(kMakeFrontWindow), kNoGoAway, 0);
  2289.   IF NOT CreateOffscreenBitMap(offscreen,myWindow^.portRect) THEN BEGIN 
  2290.     SysBeep(1);
  2291.     ExitToShell;
  2292.   END;
  2293.   { Example drawing to our off-screen bitmap }
  2294.   SetPort(offscreen);
  2295.   OSRect := offscreen^.portRect;    { offscreen bitmap's local coordinate rect }
  2296.   ovalRect := OSRect;
  2297.   FillOval(ovalRect, black);
  2298.   InsetRect(ovalRect, 1, 20);
  2299.   FillOval(ovalRect, white);
  2300.   InsetRect(ovalRect, 40, 1);
  2301.   FillOval(ovalRect, black);
  2302.   WITH ovalRect DO
  2303.     MoveTo((left+right-StringWidth(myString)) DIV 2, (top+bottom-12) DIV 2);
  2304.   TextMode(srcXor);
  2305.   DrawString(myString);
  2306.   { copy from the off-screen bitmap to the on-screen window.  Note that in this
  2307.   case the source and destination rects are the same size and both cover the
  2308.   entire area.  These rects are allowed to be portions of the source and/or
  2309.   destination and do not have to be the same size.  If they are not the same size
  2310.   then _CopyBits scales the image accordingly
  2311.   }
  2312.   SetPort(myWindow);
  2313.   CopyBits(offscreen^.portBits, myWindow^.portBits,
  2314.            offscreen^.portRect, myWindow^.portRect, srcCopy, NIL);
  2315.   DestroyOffscreenBitMap(offscreen);    {remove the evidence}
  2316.   WHILE NOT Button DO;                  {give user a chance to see the results}
  2317. END.
  2318. MPW C
  2319. First, let’s look at a general purpose function to create an off-screen bitmap.  This function creates the GrafPort on the heap.  You could also create it on the stack and pass the uninitialized structure to a function similar to this one.
  2320. Boolean CreateOffscreenBitMap(GrafPtr *newOffscreen, Rect *inBounds)
  2321. {
  2322.   GrafPtr savePort;
  2323.   GrafPtr newPort;
  2324.   GetPort(&savePort);    /* need this to restore thePort after OpenPort */
  2325.   newPort = (GrafPtr) NewPtr(sizeof(GrafPort));    /* allocate the grafPort */
  2326.   if (MemError() != noErr)
  2327.     return false;                 /* failed to allocate the off-screen port */
  2328.   /*
  2329.   the call to OpenPort does the following . . . 
  2330.     allocates space for visRgn (set to screenBits.bounds) and clipRgn (set wide open)
  2331.     sets portBits to screenBits
  2332.     sets portRect to screenBits.bounds
  2333.     etc. (see IM I-163,164)
  2334.     side effect: does a SetPort(&offScreen)
  2335.   */
  2336.   OpenPort(newPort);
  2337.   /* make bitmap the size of the bounds that caller supplied */
  2338.   newPort->portRect = *inBounds;
  2339.   newPort->portBits.bounds = *inBounds;
  2340.   RectRgn(newPort->clipRgn, inBounds);    /* avoid wide-open clipRgn, to be safe  */
  2341.   RectRgn(newPort->visRgn, inBounds);     /* in case newBounds is > screen bounds */
  2342.   /* rowBytes is size of row, it must be rounded up to an even number of bytes */
  2343.   newPort->portBits.rowBytes = ((inBounds->right - inBounds->left + 15) >> 4) << 1;
  2344.   /* number of bytes in BitMap is rowBytes * number of rows */
  2345.   /* see notes at end of Technical Note about using _NewHandle rather than _NewPtr */
  2346.   newPort->portBits.baseAddr =
  2347.            NewPtr(newPort->portBits.rowBytes * (long) (inBounds->bottom - inBounds->top));
  2348.   if (MemError()!=noErr) {   /* check to see if we had enough room for the bits */
  2349.     SetPort(savePort);
  2350.     ClosePort(newPort);      /* dump the visRgn and clipRgn */
  2351.     DisposPtr((Ptr)newPort); /* dump the GrafPort */
  2352.     return false;            /* tell caller we failed */
  2353.     }
  2354.   /* since the bits are just memory, let's clear them before we start */
  2355.   EraseRect(inBounds);     /* OpenPort did a SetPort(newPort) so we are ok */
  2356.   *newOffscreen = newPort;
  2357.   SetPort(savePort);
  2358.   return true;               /* tell caller we succeeded! */
  2359. }
  2360. Here is the function to get rid of an off-screen bitmap created by the previous function:
  2361. void DestroyOffscreenBitMap(GrafPtr oldOffscreen)
  2362. {
  2363.   ClosePort(oldOffscreen);                       /* dump the visRgn and clipRgn */
  2364.   DisposPtr(oldOffscreen->portBits.baseAddr);    /* dump the bits */
  2365.   DisposPtr((Ptr)oldOffscreen);                  /* dump the port */
  2366. }
  2367. Now that you know how to create and destroy an off-screen bitmap, let’s go through the motions of using one.  First, let’s define a few things to make the _NewWindow call a little clearer.
  2368. #define kIsVisible true
  2369. #define kNoGoAway false
  2370. #define kNoWindowStorage 0L
  2371. #define kFrontWindow ((WindowPtr) -1L)
  2372. Here’s the body of the test code:
  2373. main()
  2374. {
  2375.   char* myString = "\pThe EYE";  /* string to display */
  2376.   GrafPtr   offscreen;           /* our off-screen bitmap */
  2377.   Rect      ovalRect;            /* used for example drawing */
  2378.   Rect      myWBounds;           /* for creating window */
  2379.   Rect      OSRect;              /* portRect and bounds for off-screen bitmap*/
  2380.   WindowPtr myWindow;
  2381.   InitToolbox();                 /* exercise for the reader */
  2382.   myWBounds = qd.screenBits.bounds;  /* size of main screen */
  2383.   InsetRect(&myWBounds, 50,50);  /* make it fit better */
  2384.   myWindow = NewWindow(kNoWindowStorage, &myWBounds, "\pTest Window", kIsVisible,
  2385.                        noGrowDocProc, kFrontWindow, kNoGoAway, 0);
  2386.   if (!CreateOffscreenBitMap(&offscreen, &myWindow->portRect)) {
  2387.     SysBeep(1);
  2388.     ExitToShell();
  2389.     }
  2390.   /* Example drawing to our off-screen bitmap*/
  2391.   SetPort(offscreen);
  2392.   OSRect = offscreen->portRect;  /* offscreen bitmap's local coordinate rect */
  2393.   ovalRect = OSRect;
  2394.   FillOval(&ovalRect, qd.black);
  2395.   InsetRect(&ovalRect, 1, 20);
  2396.   FillOval(&ovalRect, qd.white);
  2397.   InsetRect(&ovalRect, 40, 1);
  2398.   FillOval(&ovalRect, qd.black);
  2399.   MoveTo((ovalRect.left + ovalRect.right - StringWidth(myString)) >> 1,
  2400.          (ovalRect.top + ovalRect.bottom - 12) >> 1);
  2401.   TextMode(srcXor);
  2402.   DrawString(myString);
  2403.   /* copy from the off-screen bitmap to the on-screen window.  Note that in this
  2404.   case the source and destination rects are the same size and both cover the
  2405.   entire area.  These rects are allowed to be portions of the source and/or
  2406.   destination and do not have to be the same size.  If they are not the same size
  2407.   then _CopyBits scales the image accordingly.
  2408.   */
  2409.   SetPort(myWindow);
  2410.   CopyBits(&offscreen->portBits, &(*myWindow).portBits,
  2411.            &offscreen->portRect, &(*myWindow).portRect, srcCopy, 0L);
  2412.   DestroyOffscreenBitMap(offscreen);    /* dump the off-screen bitmap */
  2413.   while (!Button());     /* give user a chance to see our work of art */
  2414. }
  2415. Comments
  2416. In the example code, the bits of the BitMap structure, which are pointed to by the baseAddr field, are allocated by a _NewPtr call.  If your off-screen bitmap is close to the size of the screen, then the amount of memory needed for the bits can be quite large (on the order of 20K for the Macintosh SE or 128K for a large screen).  This is quite a lot of memory to lock down in your heap and it can easily lead to fragmentation if you intend to keep the off-screen bitmap around for any length of time.  One alternative that lessens this problem is to get the bits via _NewHandle so the Memory Manager can move them when necessary.  To implement this approach, you need to keep the handle separate from the GrafPort (for example, in a structure that combines a GrafPort and a Handle).  When you want to use the off-screen bitmap you would then lock the handle and put the dereferenced handle into the baseAddr field.  When you are not using the off-screen bitmap you can then unlock it.
  2417. This example does not demonstrate one of the more typical uses of off-screen bitmaps, which is to preserve the contents of windows so that after a temporary window or dialog box obscures part of your windows and is then dismissed, you can quickly handle the resulting update events without recreating all of the intermediate drawing commands.
  2418. Make sure you only restore the pixels within the content regions of your own windows in case the temporary window partly obscures windows belonging to other applications or to the desktop.  Another application could change the contents of its windows while they are behind your temporary window, so you cannot simply restore all the pixels that were behind the temporary window because that would restore the old contents of the other application’s windows.  Instead, you could keep keep an off-screen bitmap for each of your windows and then restore them by copying each bit map into the corresponding window’s ports when they get their update events.
  2419. An alternate method is to make a single off-screen bitmap that is as large as the temporary window and a region that is the union of the content regions of your windows.  Before you display the temporary window, copy the screen into the off-screen bit map using the region as a mask.  After the temporary window is dismissed, restore the obscured area by copying from the off-screen bit map into a copy of the Window Manager port, and use the region as a mask.  If the region has the proper shape and location, it prevents _CopyBits from drawing outside of the content regions of your windows.  See Technical Note #194, WMgrPortability for details about drawing across windows.
  2420. In some cases it can be just as fast and convenient to simply define a picture (PICT) and then draw it into your window when necessary.  There are cases, however, such as text rotation, where it is advantageous to do the drawing off the screen, manipulate the bit image, and then copy the result to the visible window (thus avoiding the dangers inherent in writing directly to the screen).  In addition, this technique reduces flicker, because all of the drawing done off the screen appears on the screen at once.
  2421. It is also important to realize that, if you plan on using the pre-Color QuickDraw eight-color model, an off-screen bitmap loses any color information and you do not see your colors on a system that is capable of displaying them.  In this case you should either use a PICT to save the drawing information or check for the presence of Color QuickDraw and, when it is present, use a PixMap instead of a BitMap and the color toolbox calls (Inside Macintosh, Volume V) instead of the standard QuickDraw calls (Inside Macintosh, Volume I).
  2422. You may also want to refer to the OffScreen library (DTS Sample Code #15) which provides both high- and low-level off-screen bitmap support for the 128K and later ROMs.  The OffSample application (DTS Sample Code #16) demonstrates the use of this library.
  2423. Further Reference:
  2424. •    Inside Macintosh, Volumes I & IV, QuickDraw
  2425. •    Inside Macintosh, Volume V, Color QuickDraw
  2426. •    Technical Note M.IM.PrincipiaOffscreen —
  2427.         Principia Off-Screen Graphics Environments
  2428. •    Technical Note M.TB.WMgrPort —
  2429.          WMgrPortability
  2430. •    DTS Macintosh Sample Code #15, OffScreen & #16, OffSample
  2431. Old Style Colors
  2432. Imaging    M.IM.OldColors
  2433. Revised by:    Rich “I See Colors” Collyer    August 1990
  2434. Written by:    Rich “I See Colors” Collyer & Byron Han    October 1989
  2435. This Technical Note covers limitations of the original Macintosh color model (eight-color) which Inside Macintosh, Volume I-173, QuickDraw does not document.
  2436. Changes since October 1989:  Added definitions of the old-style constants.
  2437. QuickDraw has always been able to deal with color, just on a very limited basis.  Most applications have not made use of this feature, since Color QuickDraw-based Macintoshes come with a better color model.  There are, however, a few nice features which come with the old style color model.  With the old style colors, it is easy to print color on an ImageWriter with a color ribbon.  Another advantage is that developers do not have to write special-case code depending upon whether or not a machine has Color QuickDraw.
  2438. Now that you are ready to convert to the old style colors, there are a few things you should know about which do not work with old style colors.  This Note covers the limitations of using old style colors, as well as the best ways to work around these limitations.
  2439. Limitations
  2440. The most obvious limitation is that of only eight colors:  black, white, red, green, blue, cyan, yellow, and magenta.  This limitation is only a problem if you want to produce a color-intensive application; if this describes your application, then you need not read any further in this Note.
  2441. The next limitation is that off-screen buffers are not very useful.  You can draw into off-screen buffers, but there is no way to get the colors back from the buffer.  This leads into the next limitation, which is that _CopyBits cannot copy more than one color at a time.
  2442. When you call _CopyBits from an off-screen buffer to your window, you need to set the forecolor to the color you want to copy before calling _CopyBits (i.e., to copy a red object, call _ForeColor(redColor)).  Now when you copy the object, you can only copy one color.  If you copy different colored objects at one time, then you have a problem.  The result of a multicolored copy is that all objects copy in the same color, that of the foreground.
  2443. It is possible to work with an off-screen buffer and the old style colors, but it requires a lot of extra work.  Unless the objects are really complex, then it is probably easier to just draw the objects directly into your window.
  2444. One other limitation does exist.  Consider the following code sample.  One would assume that this sample would work at all times.
  2445.     SetPort (myPort);
  2446.     savedFG := myPort^.fgColor;
  2447.     ForeColor (redColor);            {or any other color}
  2448.     {...drawing takes place here...}
  2449.     ForeColor (savedFG);
  2450. Surprise.  It does not always work.  The saved value for the fgColor field of the GrafPort is not a classic QuickDraw color if the GrafPort is actually a CGrafPort.  If dealing with a CGrafPort, the fgColor field actually contains the foreground color’s entry in the color table, so the second call to _ForeColor really messes things up.
  2451. The proper way to set and reset the foreground color with classic QuickDraw’s _ForeColor call is as follows:
  2452.     SetPort (myPort);
  2453.     savedFG := myPort^.fgColor;
  2454.     ForeColor (redColor);            {or any other color}
  2455.     {...drawing takes place here...}
  2456.     myPort^.fgColor := savedFG;      {manually stuff the old fgColor back}
  2457.     If (32BQD = TRUE) Then           {32BQD is a flag which is made and set by}
  2458.         PortChanged (myPort);        {the application; to set it, the application}
  2459.                                      {needs to check _Gestalt for 32-Bit QuickDraw}
  2460. This Note also applies to the routine _BackColor.
  2461. What Works
  2462. The easiest way to work with these limited colors is to use pictures.  When you draw the images, you should draw into a picture.  Then when you want to draw the images into your window or to a printer, call _DrawPicture.  Pictures work well with the old style colors, and you don’t need to worry about making sure that the forecolor is current when you draw into your window.
  2463. Once you have the picture, you can use it to draw into the screen or to the printer port.  You can also set the WindowRecords windowPic to equal your PictureHandle so updates are handled by the Window Manager.
  2464. What Do Those Constants Mean Anyway
  2465. Each of the constants contains nine bits of information, and each bit has a special meaning.  Figure 1 illustrates the meaning of each of the bits, while Table 1 shows how each of the color constants fills in the appropriate bits.
  2466. Figure 1–Bit Definitions
  2467.     black    white    red    green    blue    cyan    magenta    yellow
  2468.     (33)    (30)    (209)    (329)    (389)    (269)    (149)    (89)
  2469. Cyan    0    0    0    1    1    1    0    0
  2470. Magenta    0    0    1    0    1    0    1    0
  2471. Yellow    0    0    1    1    0    0    0    1
  2472. Black    1    0    0    0    0    0    0    0
  2473. Red    0    1    1    0    0    0    1    1
  2474. Green    0    1    0    1    0    1    0    1
  2475. Blue    0    1    0    0    1    1    1    0
  2476. Inverse    0    1    0    0    0    0    0    0
  2477. Normal    1    0    1    1    1    1    1    1
  2478. Table 1–Color-Bit Correlation
  2479. Further Reference:
  2480. •    Inside Macintosh, Volume I-173, QuickDraw
  2481. •    Technical Note M.IM.Copybits —
  2482.         Of Time and Space and _CopyBits
  2483. Things You Wanted to Know About _PackBits*
  2484.     *But Were Afraid to Ask
  2485. Imaging    M.IM.PackBits
  2486. Revised by:    Guillermo Ortiz, Jon Zap, and Forrest Tanaka    January 1992
  2487. Written by:    Cameron Birse    November 1987
  2488. This Technical Note describes the format of data packed by the Toolbox utility _PackBits and documents a change to the srcBytes limit and possible worst case. Although you can simply unpack this data using _UnPackBits, Apple provides this information for the terminally curious and for those manipulating MacPaint® documents or PICT files by hand. 
  2489. Warning: This format information is subject to change.
  2490. Changes since November 1990: A warning has been added about the handling of a flag-counter byte value of -128.
  2491. Length Doesn’t Matter
  2492. Inside Macintosh, Volume I-470, describes the Pascal interface to the _PackBits trap as follows:
  2493.     PROCEDURE PackBits(VAR srcPtr,dstPtr:Ptr; srcBytes:INTEGER);
  2494. The accompanying text states that srcBytes, the length of your uncompressed data, should not be greater than 127, and that in the worst case, the compressed data can be srcBytes + 1. To pack more than 127 bytes, you had to break the data up into 127-byte groups and call _PackBits on each group. Beginning with system software version 6.0.2, this limit of 127 bytes is no longer valid. The new limit is 32,767 bytes, which is the maximum positive number that srcBytes can hold. The worst case can be determined according to the following formula:
  2495.     (srcBytes + (srcBytes+126) DIV 127)
  2496. which is comparable to what you would get if you broke up the data into 127-byte groups and picked up an additional byte for each group.
  2497. Mommy, How Do They Make Packed Bits?
  2498. The first byte is a flag-counter byte that specifies whether or not the the following data is packed, and the number of bytes involved. If this first byte is a negative number, then the following data is packed. In this case, the number is the two’s complement of a zero-based count of the number of times the data byte repeats when expanded. There is one data byte following this first byte in packed data. The byte after the data byte is the next flag-counter byte.
  2499. If the flag-counter byte is a positive number, then the following data is unpacked. In this case, the number is a zero-based count of the number of incompressible data bytes that follow. There are (flag-counter+1) data bytes following the flag-counter byte. The byte after the last data byte is the next flag-counter byte.
  2500. Note that there is no way to know, given a pointer to the start of packed data, when you have reached the end of the packed data. This is why you need to know either the length of the packed or unpacked data before you start unpacking. _UnPackBits requires the length of the unpacked data.
  2501. Warning:    _PackBits never generates the value -128 ($80) as a flag-counter byte, but a few PackBits-like routines that are built into some applications do. _UnpackBits handles this situation by skipping any flag-counter byte with this value and interpreting the next byte as the next flag-counter byte. If you’re writing your own UnpackBits-like routine, make sure it handles this situation in the same way.
  2502. Consider the following example:
  2503. Unpacked data:
  2504.     AA AA AA 80 00 2A AA AA AA AA 80 00 2A 22 AA AA AA AA AA AA AA AA AA AA
  2505. After being packed by _PackBits:
  2506.     FE AA                    ; (-(-2)+1) = 3 bytes of the pattern $AA
  2507.     02 80 00 2A              ; (2)+1 = 3 bytes of discrete data
  2508.     FD AA                    ; (-(-3)+1) = 4 bytes of the pattern $AA
  2509.     03 80 00 2A 22           ; (3)+1 = 4 bytes of discrete data
  2510.     F7 AA                    ; (-(-9)+1) = 10 bytes of the pattern $AA
  2511.        or
  2512.     FE AA 02 80 00 2A FD AA 03 80 00 2A 22 F7 AA
  2513.     *     *           *     *              *
  2514. The bytes with the asterisk (*) under them are the flag-counter bytes. _PackBits packs the data only when there are three or more consecutive bytes with the same data; otherwise it just copies the data byte for byte (and adds the count byte).
  2515. Note:    The data associated with some PICT opcodes, $0098 (PackBitsRect) and $0099 (PackBitsRgn), contain PixData which is basically made of _PackBits data. It should be noted, though, that the format for PixData includes a byteCount or length in addition to the data described in this Note.
  2516. For example, the following is the result of decoding a sample PICT2:
  2517. data 'PICT' (25534) {
  2518.     0936 0000 0000 0007 001E                /* pic size, picFrame */
  2519.     0011 02FF                               /* pict2              */
  2520.     0C00                                    /* header             */
  2521.          FFFF FFFF 0000 0000 0000 0000 001E 0000 0007 0000 0000 0000
  2522.     001E                                    /* def hilite         */
  2523.     0001                                    /* clipRgn            */
  2524.          000A 0000 0000 0007 001E
  2525.     0098                                    /* PackBitsRect       */
  2526.          801E                               /* rowbytes of 30     */
  2527.          0000 0000 0007 001E                /* Bounds             */
  2528.          0000                               /* packType           */
  2529.          0000                               /* version            */
  2530.          0000 0000                          /* packSize           */
  2531.          0048 0000                          /* hRes               */
  2532.          0048 0000                          /* vRes               */
  2533.          0000                               /* pixelType          */
  2534.          0008                               /* pixelSize          */
  2535.          0001                               /* cmpCount           */
  2536.          0008                               /* cmpSize            */
  2537.          0000 0000                          /* planeBytes         */
  2538.          0000 1F10                          /* pmTable            */
  2539.          0000 0000                          /* pmReserved         */
  2540.         /*color table*/
  2541.               0000 4CBC                     /* ctSeed             */
  2542.               8000                          /* ctFlags            */
  2543.               00FF                          /* ctSize             */
  2544.                    0000 FFFF FFFF FFFF
  2545.                    ...                 /* 254 ColorSpec's omitted */
  2546.                    0000 0000 0000 0000
  2547.          0000 0000 0007 001E                /* srcRect            */
  2548.          0000 0000 0007 001E                /* dstRect            */
  2549.          0000                               /* srcCopy            */
  2550.          /* Now we have the scan line data packed as follows:
  2551.             [bytecount for current scan line] [data as defined above]
  2552.             If rowBytes is > 250 then byteCount is a word else is a byte
  2553.             (in this case, byteCount is a byte)
  2554.             note that each unpacked row adds to 30 rowBytes
  2555.          */
  2556.          /* line 1, byte count is 2 (best case for a row)   */
  2557.          02
  2558.             E3 FF                /* -(-29) + 1 = 30 FF's    */
  2559.          /* line 2, byte count is 19 (0x13)                 */
  2560.          13
  2561.             01 FF 23             /* 1+1 data bytes          */
  2562.             FE 00                /* -(-2)+1 0's             */
  2563.             FC 23                /* -(-4)+1 0x23's          */
  2564.             FE 00                /* 3 0's                   */
  2565.             FC 23                /* 5 0x23's                */
  2566.             FE 00                /* 3 0's                   */
  2567.             FC 23                /* 5 0x23's                */
  2568.             FE 00                /* 3 0's                   */
  2569.             00 FF                /* 1 data byte             */
  2570.          /* line 3, byte count is 28                        */
  2571.          1C
  2572.             02 FF 00 23          /* 3 data bytes            */
  2573.             FE 00                /* 3 0's                   */
  2574.             FE 23                /* 3 0x23's                */
  2575.             01 00 23             /* 2 data bytes            */
  2576.             FE 00                /* 3 0's                   */
  2577.             FE 23                /* 3 0x23's                */
  2578.             01 00 23             /* 2 data bytes            */
  2579.             FE 00                /* 3 0's                   */
  2580.             FE 23                /* 3 0x23's                */
  2581.             04 00 23 00 00 FF    /* 5 data bytes            */
  2582.          /* line 4, byte count is 31 (worst case for a row) */
  2583.          1F
  2584.             03 FF 00 00 23       /* 4 data bytes            */
  2585.             FE 00                /* 3 0's                   */
  2586.             00 23                /* 1 data byte             */
  2587.             FE 00                /* 3 0's                   */
  2588.             00 23                /* 1 data byte             */
  2589.             FE 00                /* 3 0's                   */
  2590.             00 23                /* 1 data byte             */
  2591.             FE 00                /* 3 0's                   */
  2592.             00 23                /* 1 data byte             */
  2593.             FE 00                /* 3 0's                   */
  2594.             00 23                /* 1 data byte             */
  2595.             FE 00                /* 3 0's                   */
  2596.             02 23 00 FF          /* 3 data bytes            */
  2597.          /* line 5, byte count is 28                        */
  2598.          1C
  2599.             01 FF 00             /* 2 data bytes            */
  2600.             FE 23                /* 3 0x23's                */
  2601.             01 00 23             /* 2 data bytes            */
  2602.             FE 00                /* 3 0's                   */
  2603.             FE 23                /* 3 0x23's                */
  2604.             01 00 23             /* 2 data bytes            */
  2605.             FE 00                /* 3 0's                   */
  2606.             FE 23                /* 3 0x23's                */
  2607.             01 00 23             /* 2 data bytes            */
  2608.             FE 00                /* 3 0's                   */
  2609.             FE 23                /* 3 0x23's                */
  2610.             00 FF                /* 1 data byte             */
  2611.          /* line 6, byte count is 18                        */
  2612.          12
  2613.             00 FF                /* 1 data byte             */
  2614.             FC 23                /* 5 0x23's                */
  2615.             FE 00                /* 3 0's                   */
  2616.             FC 23                /* 5 0x23's                */
  2617.             FE 00                /* 3 0's                   */
  2618.             FC 23                /* 5 0x23's                */
  2619.             FE 00                /* 3 0's                   */
  2620.             FD 23                /* 4 0x23's                */
  2621.             00 FF                /* 1 data byte             */
  2622.          /* line 7, byte count is 2 (best case for a row)   */
  2623.          02
  2624.             E3 FF                /* 30 0xFF's               */
  2625.          00  /* pad so next command starts at word boundary */
  2626.     00FF                         /*end of pic               */
  2627. };
  2628. Further Reference:
  2629. •    Inside Macintosh, Volume I-465, The Toolbox Utilities
  2630. •    Inside Macintosh, Volume V-39, Color QuickDraw
  2631. •    Technical Note M.PT.MacPaintDoc —
  2632.          MacPaint Document Format
  2633. MacPaint is a registered trademark of Claris Corporation.
  2634. Palette Manager Changes in System 6.0.2
  2635. Imaging    M.IM.PaletteManagerChanges
  2636. Written by:    Guillermo Ortiz    October 1988
  2637. This Technical Note describes the changes and enhancements to the Palette Manager in System Software 6.0.2 and future versions.
  2638. Application Palette
  2639. Applications now have the ability to define a default palette for the system to use when it needs to define the color environment (i.e., when it creates a color window without an associated palette or displays a dialog box).
  2640. The application palette feature is especially cool in cases where a color application uses old-style dialogs and alerts because without an application palette, the system will use the default palette to define the color environment.  Since the system uses the default palette, the color environment may change (will change in 16-color mode) to cause some “cosmic” colors to appear in the active window.  Defining a default application palette with two colors, black and white, solves this problem.
  2641. If the system needs a palette to define a color environment, it looks in the resource fork of the application for the 'pltt' ID = 0 resource and uses the palette which it contains.  If the system cannot find this resource in the application’s resource fork, it will use its own default palette (resource 'pltt' ID = 0 in the System file) if present, or, if necessary, it will use the Palette Manager’s built-in palette.
  2642. Once an application has set its color environment (by calling _InitMenus, or _InitPalettes in weird instances when there are no menus) it can find the default palette by calling GetPalette ( WindowPtr (-1) ) or change the default palette by calling SetPalette ( WindowPtr (-1), newDefPltt, true ).  Note that the initialization of the Palette Manager with a call to _InitMenus is contrary to the way Inside Macintosh, Volume V, The Palette Manager documents it.
  2643. One Palette, Many Ports
  2644. You can now associate one palette with many CGrafPort and CWindow records, thus simplifying the use of a single palette with multiple ports and windows; System Software 6.0 and earlier require copies of the palette to use it with different windows.
  2645. Although this ability to associate one palette with multiple ports and windows will allow the use of calls like _PmForeColor and _PmBackColor, calling _ActivatePalette with an off-screen port does nothing, and as a result, calling it with an off-screen port will associate the palette with the port but will not cause any change in the color environment.
  2646. One important implication of this feature is that DisposeWindow (_DisposWindow) will not dispose of the associated palette automatically since it may be allocated to other ports or windows.  The only exception to this behavior is when an application has used _GetNewCWindow to create the window, there is a 'pltt' resource with the same ID as the window, and the application has not called _GetPalette for the window.
  2647. Color Updates
  2648. System version 6.0.2 also introduces a new call, _NSetPalette, which complements _SetPalette.  _NSetPalette has the same functionality as _SetPalette, but the CUpdates parameter has been modified from a Boolean to an Integer as follows:
  2649. PROCEDURE NSetPalette (dstWindow: WindowPtr; srcPalette: PaletteHandle;
  2650.     nCUpdates: INTEGER);
  2651. INLINE $AA95;
  2652. _NSetPalette changes the palette associated with dstWindow to srcPalette.  It also records whether the window wants to receive updates as a result of a change to its color environment.  If you want dstWindow to be updated whenever its color environment changes, set nCUpdates to pmAllUpdates.  If you are only interested in updates when dstWindow is the active window, set nCUpdates to pmFgUpdates.  If you are only interested in updates when dstWindow is not the active window, set nCUpdates to pmBkUpdates.
  2653. { NSetPalette Update Constants }
  2654. pmNoUpdates =     $8000;    {no updates}
  2655. pmBkUpdates =     $A000;    {background updates only}
  2656. pmFgUpdates =     $C000;    {foreground updates only}
  2657. pmAllUpdates =     $E000;    {all updates}
  2658. _SetPalette retains its syntax and function:
  2659. PROCEDURE SetPalette (dstWindow: WindowPtr; srcPalette: PaletteHandle;
  2660.     CUpdates: Boolean);
  2661. INLINE $AA95;
  2662. Note:    The trap words for _NSetPalette and _SetPalette are identical.
  2663. CopyPalette
  2664. PROCEDURE CopyPalette (srcPalette, dstPalette: PaletteHandle;
  2665.     srcEntry,dstEntry,dstLength: INTEGER);
  2666. INLINE $AAA1;
  2667. _CopyPalette is a utility procedure that copies dstLength entries from the source palette into the destination palette; the copy begins at srcEntry and dstEntry, respectively.  _CopyPalette will resize the destination palette when the number of entries after the copy is greater than the original.
  2668. _CopyPalette does not call _ActivatePalette, so the application is free to do a number of palette changes without causing a series of intermediate changes to the color environment; the application should call _ActivatePalette after completing all palette changes.
  2669. If either of the palette handles are NIL, _CopyPalette does nothing.
  2670. Palette Manager Q&As
  2671. Imaging    M.IM.PaletteMgr.Q&As
  2672. Revised by:    Developer Support Center    October 1992
  2673. Written by:    Developer Support Center    October 1990
  2674. This Technical Note contains a collection of Q&As relating to a specific topic—questions you’ve sent the Developer Support Center (DSC) along with answers from the DSC engineers. While DSC engineers have checked the Q&A content for accuracy, the Q&A Technical Notes don’t have the editing and organization of other Technical Notes. The Q&A function is to get new technical information and updates to you quickly, saving the polish for when the information migrates into reference manuals.
  2675. Q&As are now included with Technical Notes to make access to technical updates easier for you. If you have comments or suggestions about Q&A content or distribution, please let us know by sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical questions about Q&A content to DEVSUPPORT for resolution.
  2676. New Q&As and Q&As revised this month are marked with a bar in the side margin.
  2677. Macintosh Palette Manager and offscreen graphics
  2678. Written:    7/22/91
  2679. Last reviewed:    8/1/92
  2680. The Macintosh Palette Manager doesn’t work on offscreen environments the way you’d expect. Unlike color windows, SetPalette will not change the offscreen’s color table; rather it just allows you to use PMForeColor and PMBackColor to set the current drawing color in that environment. To change the offscreen’s color table you’ll need to convert the palette to a color table and then set the resulting color table to the off screen. Calling Palette2CTab will do the converting for you.
  2681. To get around having to use palettes to define the current drawing color in the off screen, you can always use Index2Color and then RGBForeColor to get the color to be set for drawing. A remake of GiMeDaPalette code sample, available on the latest Developer CD Series disc, does offscreen drawing in place of having to continually copy a PICT.
  2682. RestoreDeviceClut and color flash when application quits
  2683. Written:    8/23/91
  2684. Last reviewed:    8/1/92
  2685. When my application, which uses a color palette, quits, there is momentary but distracting flash of weird colors in the Finder windows and the desktop temporarily appears in a weird color. Is there any way to get around this?
  2686. ___
  2687. When you quit, RestoreDeviceClut is called to restore the color table and an update event is called to redraw the screen. It’s the delay between the change in the color table and the update event that causes the flash of incorrect colors to be displayed. This, unfortunately, is unavoidable.
  2688. Restoring Finder desktop colors after using Palette Manager
  2689. Written:    8/28/91
  2690. Last reviewed:    8/1/92
  2691. After using the Macintosh Palette Manager, how do I restore the Finder’s desktop colors?
  2692. ___
  2693. The Finder desktop’s colors are restored automatically on quitting applications that use the Palette Manager. Colors aren’t restored automatically when switching from your application to another, but if that application needs a certain set of colors and uses the Palette Manager to get them, then it’ll have them the moment it comes to the front. If you’re concerned about applications that don’t use the Palette Manager, you can use RestoreDeviceClut(gd:GDHandle), passing the handle to the GDevice of the screen you want to reset, or nil if you want to reset all of your devices. Passing nil to RestoreDeviceClut is your best bet, as it is very straightforward, and resets all of your monitors. You may not wish to do this, however, because RestoreDeviceClut is only available on machines with 32-bit color QuickDraw.
  2694. To reset a screen’s GDevice for machines without 32-bit color QuickDraw, you will need to keep track of the color table.When your application starts up, get the GDevice’s color table and save it—you’ll need it later. This value can be found at (**(**GDHandle).gdPMap).pmTable, where gdPMap is a PixMapHandle, and pmTable is a CTabHandle which tells you the absolute colors for this image. These data structures are found in Inside Macintosh Volume V, pages 52 and 119.
  2695. Build your application’s “world” using the Palette Manager, and avoid low-level methods of changing colors. When your application is about to quit and you want to restore the environment to its original state, get the color table you saved in the beginning. Convert this to a palette using CTab2Palette. Then set your window to this palette with SetPalette. This will cause the environment to update to the original color table that you initially got from the GDevice. If the application that is behind your application is Palette Manager friendly, then it will restore the environment to its palette. You may also want to do this procedure at the suspend event, as shown in the DTS sample MacApp program, FracApp. One of the problems that you won’t be able to solve this way involves multiple monitors. You won’t know which one to update. Only the monitor that has the window that you’ve called ActivatePalette on will update.
  2696. If your application changes the color environment with the Palette Manager, then RestoreDeviceClut is called automatically when your application quits. This means that you shouldn’t have to worry about restoring the palette if you don’t want to. There is a catch, however (there always is). When you use the SADE version of MultiFinder (6.1b9), it prevents this from automatically happening. Other versions of MultiFinder don’t have this side effect.
  2697. SetPalette cUpdates, NSetPalette, and window update events
  2698. Written:    9/26/91
  2699. Last reviewed:    8/1/92
  2700. When I pass false in the cUpdates parameter to SetPalette, I still get update events to that window when I modify its palette. What’s going on?
  2701. ___
  2702. SetPalette’s cUpdates parameter controls whether color-table changes cause that window to get update events only if that window is NOT frontmost. If that window is frontmost, then any changes to its palette causes it to get an update event regardless of what the cUpdates parameter is. When you call SetEntryColor and then ActivatePalette for your front-most window, it gets an update event because it’s the front-most window even though you passed false in the cUpdates parameter. Another important point is that windows that don’t have palettes also get update events even when another window’s palette is activated.
  2703. Fortunately, system software version 6.0.2 introduced the NSetPalette routine, which you can find documented in the Macintosh Technical Note “Palette Manager Changes in System 6.0.2,” and on page 20-20 in the revamped Palette Manager chapter of Inside Macintosh Volume VI. This variation of SetPalette gives you a lot more flexibility in controlling whether your window gets an update event than SetPalette does. If you pass pmAllUpdates in the nCUpdates parameter, then that window gets an update event when either it or another window’s palette is activated. If you pass pmFgUpdates, then it gets an update event when a palette is activated only if it’s the front-most window (in effect, it only gets an update event if its own palette is activated). If you pass pmBkUpdates, then it gets an update event when a palette is activated only if it’s not the front-most window (in effect, it only gets an update event if another window’s palette is activated). If you pass pmNoUpdates, then that window never gets an update event from any window’s palette being activated, including that window itself.
  2704. Picture Comments—The Real Deal
  2705. Imaging    M.IM.PictComments
  2706. Revised by:    Joseph Maurer    October 1992
  2707. Written by:    Ginger Jernigan    November 1986
  2708. Changes since March 1988: This Note (formerly titled “Optimizing for the LaserWriter—PicComments”) describes the picture comments defined and interpreted by the Apple printer drivers. Most of the picture comments are specific to PostScript, but we renamed the Note to emphasize that LaserWriter printers are not necessarily PostScript devices, and that QuickDraw printer drivers may implement their own picture comment handling. This Note has been completely rewritten and incorporates all additional insights gained during the last few years. We are also much more determined now to discourage the use of obsolete and problem-laden (although still supported) picture comments, and we carefully point out known problems or limitations of each comment.
  2709. Introduction
  2710. The QDProcs record (see Inside Macintosh Volume I, page 197) reflects the foundations of the architecture of QuickDraw. The commentProc field points to a procedure that processes picture comments, as included in a picture by means of the PicComment procedure (Inside Macintosh Volume I, page 189). This allows applications to include application-specific additional information in the pictures they create.
  2711. The QDProcs record also is the key to understanding how Macintosh printer drivers work. When the application calls PrOpenPage and draws into the printing grafPort, the printer driver collects the drawing commands by hooking into the QDProcs of the printing port. In particular, if an application calls the PicComment procedure while drawing into the printing grafPort, the printer driver gets a chance to capture and process the information contained in the kind and dataHandle parameters.
  2712. During the development of the original LaserWriter driver, it became obvious that applications should be able to take advantage of certain PostScript features that were not accessible through standard QuickDraw calls, such as rotated text and graphics, dashed lines, fractional line widths, and smoothed polygons. Also, certain applications needed a way to transmit their own native PostScript instructions to the printer. Picture comments seemed to be the ideal vehicle for providing these capabilities.
  2713. Unfortunately, there are conflicts with the device-independent nature of the Macintosh Printing Manager architecture. In this Note, we still want to document picture comments as completely and correctly as possible; and we want to tell you how to use the best of their features, while maintaining the important goal of device-independent printing and all- purpose PICTs. (This is why it has such a painful history!)
  2714. First, we give an overview of the picture comments as currently implemented by Apple’s printer drivers. This leads us immediately to the problem section “Cohabitation of QuickDraw and PostScript,” which also shows how to keep the QuickDraw and PostScript graphics states synchronized during printing. Finally, we discuss all the picture comments by subject, in the order suggested by Table 1.
  2715. Picture Comments Repertoire
  2716. The following picture comments are recognized by all PostScript LaserWriter drivers version 3.1 and later. 
  2717. Table 1  PostScript LaserWriter Picture Comments
  2718.             Data         
  2719.     Type    Kind    Size    Data    Description
  2720.     TextBegin    150    6    TTxtPicRec    Begin text function
  2721.     TextEnd    151    0    NIL    End text function
  2722.     StringBegin    152    0    NIL    Begin string delimitation
  2723.     StringEnd    153    0    NIL    End string delimitation    TextCenter    154    8    TTxtCenter    Offset to center of rotation
  2724.     LineLayoutOff    155    0    NIL    Turn LaserWriter line layout off
  2725.     LineLayoutOn    156    0    NIL    Turn LaserWriter line layout on
  2726. #    ClientLineLayout    157    16    TClientLL    Customize line layout error 
  2727.                     distribution
  2728.     PolyBegin    160    0    NIL    Begin special polygon
  2729.     PolyEnd    161    0    NIL    End special polygon
  2730.     PolyIgnore    163    0    NIL    Ignore following polygon data
  2731.     PolySmooth    164    1    PolyVerb    Close, Fill, Frame
  2732.     PolyClose    165    0    NIL    Close the polygon
  2733.     DashedLine    180    -    TDashedLine    Draw following lines as dashed
  2734.     DashedStop    181    0    NIL    End dashed lines
  2735.     SetLineWidth    182    4    Point    Set fractional line widths
  2736.     PostScriptBegin     190    0    NIL    Set driver state to PostScript
  2737.     PostScriptEnd     191    0     NIL    Restore QuickDraw state
  2738.     PostScriptHandle    192    -    PSData     PostScript data in handle
  2739. †    PostScriptFile    193    -    FileName    FileName in data handle
  2740. †    TextIsPostScript    194    0    NIL    QuickDraw text is sent as PostScript
  2741. †    ResourcePS    195    8    Type/ID/Index    PostScript data in a resource file
  2742.     PSBeginNoSave    196    0    NIL    Set driver state to PostScript
  2743. #    SetGrayLevel    197    4    Fixed    Call PostScript’s setgray operator
  2744.     RotateBegin    200    4    TRotation    Begin rotated port
  2745.     RotateEnd    201    0    NIL    End rotation
  2746.     RotateCenter    202    8    Center    Offset to center of rotation
  2747. #    FormsPrinting    210    0    NIL    Don’t clear print buffer after each page
  2748. #    EndFormsPrinting    211    0    NIL    End forms printing after PrClosePage
  2749. ______________________________________
  2750. †    These comments are obsolete.
  2751. #    These comments are not recommended.
  2752. Most of the comments in Table 1 were designed specifically for the original LaserWriter driver. In fact, the term LaserWriter has been (and often still is) used in the sense of “PostScript printer,” and the LaserWriter driver is known to be basically a QuickDraw-to-PostScript translator. Meanwhile, however, QuickDraw-based LaserWriter models came out, so we should start being more careful in our terminology. This is why we insist on talking about PostScript drivers or PostScript printers when a picture comment applies to PostScript.
  2753. QuickDraw printer drivers may implement their own picture comments, or some of the above comments, in order to provide additional capabilities. Certain third-party printer drivers implement text rotation, for example, by supporting the TextBegin/TextCenter/ TextEnd picture comments.
  2754. Apple’s QuickDraw printer driver for the LaserWriter SC supports the following three picture comments:
  2755.     LineLayoutOff    155    0    NIL    Turn LaserWriter line layout off
  2756.     LineLayoutOn    156    0    NIL    Turn LaserWriter line layout on
  2757.     SetLineWidth    182    4    Point    Set fractional line widths.
  2758. The ImageWriter LQ driver and the first versions of the StyleWriter driver (prior to 7.2) implement the LineLayoutOff and LineLayoutOn picture comments. Even the ImageWriter driver reacts to picture comments:
  2759.     BitMapThinningOff    1000    0    NIL    Turn off hi-res bitmap thinning
  2760.     BitMapThinningOn    1001    0    NIL    Turn on hi-res bitmap thinning
  2761. The ImageWriter driver does the same toggling of the “bitmap thinning” of fat bitmaps in Best mode, when it encounters a TextBegin or TextEnd comment (undocumented feature—never mind!). The ImageWriter LQ driver handles these comments similarly.
  2762. The current StyleWriter driver (version 7.2.2) and the personal LaserWriter LS driver do not support any picture comments at all. 
  2763. The point of all this is:
  2764. It is impossible to determine which picture comments
  2765. are supported by which printer driver.
  2766. In other words, your application should never assume a particular picture comment is available, but your application also should not defeat the device-independent design of the Macintosh printing architecture by writing printer driver–specific code! 
  2767. Of course, you know (Inside Macintosh Volume II, page 152) that the high byte of the prStl .wDev field of the print record identifies a printer driver species, and that a value of $03 tells you the printer driver belongs to the PostScript LaserWriter driver ancestry. As a matter of fact, many applications use this information to achieve special printing features not available through the Printing Manager interface.
  2768. And, of course, you also know that we don’t like this idea. One reason is future system software may allow spool files to be redirected to a printer other than the one chosen when you sent your printing instructions (including picture comments). Another reason is that picture comments usually are included in PICTs; documents containing such pictures should print with optimal results on any printer configuration. And, finally, you never know what the future holds for you, in terms of new printing devices or new printer drivers—or a new printing architecture!
  2769. Instead, if a picture (i.e., a sequence of imaging instructions) contains picture comments to enhance the output on devices that support them, it should also contain a standard QuickDraw representation as a fallback solution, in case the rendering device does not recognize the picture comments. The design and implementation of these picture comments should incorporate conventions to make this cohabitation of two representations in one picture possible.
  2770. Cohabitation of QuickDraw and PostScript
  2771. Device-Independent Pictures
  2772. We can think of the Printing Manager’s PrOpenPage and PrClosePage calls as being analogous to the OpenPicture and ClosePicture calls (which, by the way, reminds us to never call OpenPicture between PrOpenPage and PrClosePage; see Inside Macintosh Volume II, page 160). In both cases, a stream of imaging instructions is recorded for deferred rendering. We want to create pictures that include both QuickDraw and optimized PostScript representations so that we obtain the best results in all circumstances. We must take special care for third-party QuickDraw printer drivers that support picture comments originally intended for PostScript devices only.
  2773. Let’s start with the easy ones.
  2774. The two picture comments PostScriptBegin and PostScriptEnd clearly suggest that any imaging instructions in between are intended exclusively for PostScript printing devices. In the case of the PostScript LaserWriter driver, the effect of PostScriptBegin is to disable all bottlenecks except commentProc, txMeasProc, getPicProc, and putPicProc. This means that QuickDraw’s text, line, shape (Rects, RoundRects, Ovals, Arcs, Polygons) and bitmap drawing calls don’t have any effect in the printing grafPort when enclosed by PostScriptBegin and PostScriptEnd. Instead, the PostScript LaserWriter driver expects to receive the imaging instructions as data enclosed in the PostScriptHandle comment. This way, both the PostScript and QuickDraw representation can coexist in the same picture without conflict. As a consequence, non-PostScript printer drivers, unable to interpret general PostScript text, must not imitate this behavior of ignoring QuickDraw instructions, even when they implement other picture comments such as TextBegin and TextEnd for text rotation. Otherwise, they would miss the QuickDraw representation of some PostScript imaging.
  2775. The text rotation picture comments (TextBegin, TextCenter, TextEnd) silently include the assumption that a printer driver that supports these comments
  2776. a. ignores the QuickDraw clipping region between TextBegin and TextEnd
  2777. b. ignores the QuickDraw CopyBits instruction within TextBegin/TextEnd
  2778. This way, a bitmap representation of the rotated text can be included in the picture. It will be used only if the TextBegin/TextEnd comments are not supported. Conversely, the QuickDraw commands required to draw the text to be rotated by the printer driver are “hidden” from QuickDraw by setting the clipping region to empty, which is ignored by the driver supporting the comments.
  2779. The polygon picture comments provide another solution to the problem, in form of the special comment PolyIgnore. It allows one to include a QuickDraw representation of the smoothed polygon, ignored by a driver that supports polygon smoothing (such as via PostScript’s curve operator). And for filled polygons, QuickDraw’s region concept works around a conflict of who owns which polygon (see sample code later in this Note).
  2780. Some picture comments (such as the line layout comments) do not require a fallback solution in case they are not supported by a printer driver; or the feature, if absent, is not a big loss (such as SetLineWidth, provided you use it only for widths smaller than one 72-dot-per-inch (dpi) QuickDraw pixel). 
  2781. But for the picture comments DashedLine/DashedStop and RotateBegin/ RotateCenter/RotateEnd, there is no general solution to the “cohabitation” problem; and we are distressed about it. It is obvious that they have been defined with the PostScript LaserWriter driver in mind, without anticipating a future furnished by some 150 third-party printer drivers. The only way to include both representations in these cases is indeed to assume that only PostScript drivers will support the picture comment, such that the PostScriptBegin and PostScriptEnd comments can be used to “comment out” the QuickDraw representation.
  2782. Even under the above assumption, we still need a trick to prevent the QuickDraw calls within the scope of the picture comments from showing up when the comments are not recognized. Fortunately, early Macintosh developers discovered a QuickDraw feature that, unintentionally, solves the problem. Passing the “magic” mode 23 to PenMode inhibits QuickDraw’s normal drawing, but still lets the LaserWriter driver see the drawing instructions come through the bottlenecks, so that it can translate them into PostScript. Note that this pen mode always has been undocumented, and that using it was considered a compatibility risk and frowned upon for some time. Given the current state of affairs, however, there is no reason anymore to be paranoid about it.
  2783. Keeping QuickDraw and PostScript Synchronized
  2784. There are two situations, in the context of picture comments, where the design of the PostScript LaserWriter driver requires special precautions from the application programmer. 
  2785. First, certain QuickDraw instructions like Move, MoveTo, PenPat, and PenSize change the state of the grafPort, without going through the QDProcs bottleneck procedures. A Macin-tosh printer driver takes these changes into account only at the time it executes an actual drawing instruction. Remember, the printer driver hooks into the QDProcs to get execution time and only “sees” instructions coming through the QDProcs. Nothing is wrong with it—unless PostScript code is woven into the graphics instructions by means of picture comments. (Note that PostScript code may be generated transparently when the LaserWriter driver encounters certain picture comments.) If the PostScript code assumes that the current state of the grafPort corresponds to what you expect it to be, then you have to flush the state of the grafPort explicitly before inserting the PostScript code. This is easier than it sounds; just do something inoffensive that goes through the QDProcs.lineProc bottleneck, like in the following utility procedure:
  2786. PROCEDURE FlushGrafPortState;
  2787. { This routine causes the state of the Printing Manager's grafPort to be }
  2788. { flushed out to the LaserWriter, by making a dummy call through the     }
  2789. { QDProcs.lineProc bottleneck. Pen size and pen location are preserved.  }
  2790.    VAR
  2791.       penInfo: PenState;
  2792.    BEGIN
  2793.       GetPenState(penInfo);                              { Save pen size. }
  2794.       PenSize(0,0);                                  { Make it invisible. }
  2795.       Line(0,0);                           { Go through QDProcs.lineProc. }
  2796.       PenSize(penInfo.pnSize.h, penInfo.pnSize.v);    { Restore pen size. }
  2797.    END;
  2798. Another unwanted effect is related to the PostScript LaserWriter driver’s multiple internal buffering of generated PostScript code. The PostScript code generated for text drawing instructions (which usually involves font queries and, sometimes, font downloading) is buffered independently from the PostScript code inserted by means of picture comments. In certain cases, this results in apparently nonsequential execution of drawing instructions, and may affect clipping regions or may have side effects on the PostScript code you included in picture comments. In order to synchronize the sequence of QuickDraw instructions with the generation of PostScript code, you need to call the following procedure:
  2799. PROCEDURE FlushPostScriptState;
  2800. { This routine flushes the buffer maintained by the LaserWriter driver. }
  2801. { All PostScript, generated either by the app or by the LaserWriter     }
  2802. { driver, will be sent to the device.                                   }
  2803.    BEGIN
  2804.       PicComment(PostScriptBegin, 0, NIL);
  2805.       PicComment(PostScriptEnd, 0, NIL);
  2806.    END;
  2807. In the following discussion of picture comments, we’ll refer to these two utility routines as appropriate.
  2808. Text Rotation
  2809. Comments:    TextBegin, TextCenter, TextEnd
  2810. These comments give access to PostScript’s capabilities of rotating, flipping, and justifying text. They are intended for applications likely to be used with PostScript printers (such as desktop publishing and advanced drawing applications), but which don’t want to use PostScript explicitly. Note that some non-PostScript printer drivers support these comments as well. For situations where the comments are not supported (such as the QuickDraw screen, or most QuickDraw printer drivers), you must provide a bitmap represen-tation of the rotated text as an alternative. 
  2811. Let’s look at sample code right away.
  2812. USES  PicComments;  { See Appendix; defines constants for just and flip and   }
  2813.                     { the structures referred to by TTxtPicHdl and TCenterHdl.}
  2814.    
  2815. PROCEDURE QDStringRotation(s: Str255; ctr: Point; 
  2816.                            just, flip: Integer; rot: Fixed); EXTERNAL;
  2817. { This routine should generate a bitmap of the rotated and flipped text       }
  2818. { and use CopyBits to draw it to the grafPort. Left as an exercise ...        }
  2819. PROCEDURE DrawXString(s: Str255; ctr: Point; just, flip: Integer; rot: Fixed);
  2820. { Draws the string s rotated by rot degrees around the current point, offset  }
  2821. { by ctr, justifying and flipping according to the just and flip parameters.  }
  2822. { If the printer driver supports the TextBegin, TextCenter, and TextEnd       }
  2823. { picture comments, it rotates the text at device resolution; otherwise, the  }
  2824. { external procedure QDStringRotation is called to image the rotated string.  }
  2825. { The pen position is preserved. }
  2826.    VAR
  2827.       hT: TTxtPicHdl;     { Defined in PicComments.p - see Appendix. }
  2828.       hC: TCenterHdl;     { –"– }
  2829.       zeroRect: Rect;
  2830.       pt: Point;
  2831.       oldClip: RgnHandle;
  2832.    BEGIN
  2833.       GetPen(pt);  { to preserve the pen position }
  2834.       hT := TTxtPicHdl(NewHandle(SizeOf(TTxtPicRec)));
  2835.       hC := TCenterHdl(NewHandle(SizeOf(TCenterRec)));
  2836.       { No error handling: if these fail, we are in deep trouble anyway ...}
  2837.       WITH hT^^ DO BEGIN
  2838.          tJus      := just;
  2839.          tFlip     := flip; 
  2840.          tAngle    := - FixRound(rot); { I like counterclockwise better. }
  2841.          tLine     := 0; { reserved }
  2842.          tCmnt     := 0; { used internally by the printer driver }
  2843.          tAngleFixed := - rot;
  2844.       END;
  2845.       hC^^.y := Long2Fix(ctr.v);
  2846.       hC^^.x := Long2Fix(ctr.h);
  2847.       PicComment(TextBegin,SizeOf(TTxtPicRec),Handle(hT));
  2848.       PicComment(TextCenter,SizeOf(TCenterRec),Handle(hC));
  2849.       { PostScript graphics state now has rotated/flipped coordinates. }
  2850.       oldClip := NewRgn;
  2851.       GetClip(oldClip);
  2852.       SetRect(zeroRect,0,0,0,0);
  2853.       ClipRect(zeroRect);  { Hides the following DrawString from QuickDraw }
  2854.       DrawString(s); { in the rotated PostScript environment. }
  2855.       ClipRect(oldClip^^.rgnBBox);
  2856.       { Now the "fallback" bitmap representation; see the comments above  }
  2857.       { at the declaration of the QDStringRotation procedure. }
  2858.       QDStringRotation(s, ctr, just, flip, rot);
  2859.       PicComment(TextEnd,0,NIL); { Set environment back to the original state }
  2860.       DisposHandle(Handle(hT));
  2861.       DisposHandle(Handle(hC));
  2862.       MoveTo(pt.h,pt.v);  { to preserve the pen position }
  2863.    END;
  2864. The preceding discussion about including both QuickDraw and PostScript representations and the comments included in the source code say it all: The conventions tied to the usage of the TextBegin and TextEnd picture comments allow you to take advantage of a printer driver’s implementation of high-resolution text rotation, while including a bitmapped representation for where the comments are not supported.
  2865. Some Additional Hints
  2866. •    Because of QuickDraw’s orientation of the vertical coordinate axis, the rotation angle is measured clockwise. Nothing prevents us from using the negative angle if we are used to the counterclockwise orientation.
  2867. •    The angle is measured in degrees (0..360), and passed as a Fixed type number (that is, if taken as a LongInt value, you have to divide it by 65536 to obtain the angle in degrees). For integer angles, it is possible to use a reduced TTxtPicRec structure that does not contain the tRotFrac field. The PostScript LaserWriter driver uses GetHandleSize(hT) to determine whether it must use the fractional angle in the tRotFrac field. To be safe, always set the tRot field to FixRound(tRotFrac) if you go with the extended TTxtPicRec (as we do here).
  2868. •    It is convenient that clipping regions are ignored between the TextBegin and TextEnd picture comments, because it allows us to clip out the DrawString on printers that don’t support these comments. Unfortunately, this also means that text rotated this way can’t be clipped. If clipping of rotated text is required, you’ll have to do it entirely within PostScript.
  2869. •    Due to the LaserWriter driver’s internal buffering of generated PostScript code, the effect of ignoring clip regions may be propagated to preceding sections of your drawing instructions. We recommend calling the FlushPostScriptState procedure described earlier immediately before the TextBegin comment.
  2870. •    The tJus field in the TTxtPicRec, if different from tJusNone, tells the printer driver to maintain either the left, right, or center point of the string without recalculating the interword and intercharacter spacing. The tJusFull value specifies that the original length of the string (on the QuickDraw screen) must be maintained. This is important when the printer font has widths different from those of the screen font, and when you rotate justified blocks of text.
  2871. •    The tFlip field in the TTxtPicRec specifies horizontal or vertical flipping about the center point specified by the TextCenter comment.
  2872. •    The TextCenter comment specifies the center of rotation for any text enclosed within the TextBegin and TextEnd calls, as an offset to the location of the current point. The rotation is achieved by changing PostScript’s coordinate system. A sequence of DrawString – MoveTo instructions is rotated as a whole until TextEnd is encountered.
  2873. •    Some versions of double-byte Kanji systems print Kanji characters by calling CopyBits instead of calling standard text drawing routines. This means the comments in the Text Rotation family cannot be used with these fonts. Instead, use the Graphics Rotation comment family described later in this Note.
  2874. Line Layout Control
  2875. Comments:    LineLayoutOn, LineLayoutOff, ClientLineLayout
  2876. When drawing to a printing grafPort, the selected printer driver does a lot of work “behind the scenes” to try to maintain the infamous “What-You-See-Is-What-You-Get” (WYSIWYG) metaphor from the screen to the paper, and generally to make the printed output look as good as possible. Depending on the target device, the printer driver, and the configuration of fonts in the system, the font you draw text with may be scaled, smoothed, remapped, or even replaced by a font built into the printer. In nearly all cases where the device resolution of the printer is different from QuickDraw’s “hard-coded” 72-dpi screen resolution, the width of text rendered on the printer is different from the text width on the screen. This is due to nonproportionally scaling bitmapped fonts, different character widths after font substitution, and rounding errors of fractional character widths on the screen. The difference in the width of a line of text is called the line layout error.
  2877. The printer driver is responsible for adjusting the word and character spacing in the printed output so that the two widths are identical. If it doesn’t, apparently fully justified text on the screen may appear ragged on the paper, and certain lines of text may extend beyond the right border and be badly clipped. Many existing applications make this task really difficult for the printer drivers (don’t blame them, though!). They position the words (or even characters) separately on a line, and the printer driver has to figure out how to collect the complete line before applying its line layout algorithm to distribute the difference of the text widths into word and character spacing. Given the uneven distribution of the character width differences, and the requirement of achieving good typographical quality in the printed output, it is unavoidable that the position and width of a word within a justified line differs slightly from what appears on the screen; only the length of the whole line is maintained.
  2878. In computing the required line layout adjustments, the LaserWriter driver proceeds as follows:
  2879. 1.    It collects text coming through the printing grafPort’s textProc bottleneck, and heuristically puts it together into what it “believes” is a logically contiguous line of text. This includes text moved vertically away from the baseline, to take care of indices or exponents in the text. The process of accumulating text is stopped when the LaserWriter driver detects that the horizontal component of the pen position has changed since the previous text drawing instruction, or when picture comments like TextBegin, TextEnd, StringBegin, StringEnd are encountered.
  2880. 2.    It determines the width of the accumulated logical line of text, both on the screen and on the printer, and distributes the line layout error among the interword and intercharacter spacing of the printed output.
  2881. The LineLayoutOff picture comment disables only the second step (distribution of the line layout error); the heuristic algorithm of accumulating text into a logically contiguous piece is not affected. Otherwise, if the character widths of the printer font are different from those of the screen font, and if the text contains exponents or indices, the latter would often be misplaced.
  2882. The following code fragment shows a probably unexpected consequence of this behavior. We draw a line in two pieces three times. A vertical line shows the starting pen position of the second DrawString call. The second line is enclosed by LineLayoutOff and LineLayoutOn picture comments.
  2883. PROCEDURE ObserveLineLayout;
  2884.    CONST
  2885.       testString1 = 'Whatever you like, preferably ';
  2886.       testString2 = 'with spaces, long and short words';
  2887.       fontName = 'New York';
  2888.       fontSize = 14;
  2889.       x0 = 20; { starting point }
  2890.       y0 = 40;
  2891.       h  = 30; { line height }
  2892.    VAR
  2893.       familyID: Integer;
  2894.       w, y    : Integer;
  2895.    BEGIN
  2896.       GetFNum(fontName, familyID);
  2897.       TextFont(familyID);
  2898.       TextSize(fontSize);
  2899.  
  2900.       w := StringWidth(testString1);
  2901.       y := y0;
  2902.       MoveTo(x0 + w, y - h);
  2903.       Line(0, 4 * h);    { This is to estimate the difference. }
  2904.       { Draw the first line, in two pieces. }
  2905.       { This is the default line layout behavior of the LaserWriter driver. }
  2906.       MoveTo(x0, y);          
  2907.       DrawString(testString1);
  2908.       MoveTo(x0 + w, y);
  2909.       DrawString(testString2);
  2910.       { Draw the second line, in the same way as above. }
  2911.       { Because of the LineLayoutOff picture comment, the unmodified widths }
  2912.       { of the printer font are used. }
  2913.       y := y + h;
  2914.       PicComment(LineLayoutOff, 0, NIL);
  2915.                                    { ••• (1)  •••}
  2916.       MoveTo(x0, y);
  2917.       DrawString(testString1);
  2918.       MoveTo(x0 + w, y);
  2919.                                    { ••• (2)  •••}
  2920.       DrawString(testString2);
  2921.       y := y + h;
  2922.       PicComment(LineLayoutOn, 0, NIL);
  2923.       { Back to the original behavior. }
  2924.       MoveTo(x0, y);
  2925.       DrawString(testString1);
  2926.       MoveTo(x0 + w, y);
  2927.       DrawString(testString2);
  2928.    END;
  2929. And this is (approximately) the output of the ObserveLineLayout (with LaserWriter driver version 7.1.1, and the default setting “Font Substitution enabled”):
  2930. Figure 1—Effect of the LineLayoutOff comment
  2931. For most noticeable effects, we choose the bitmapped New York font, such that the LaserWriter driver substitutes PostScript Times (note that there are no line layout problems with TrueType fonts, unless the TrueType font has the same name and different cha-rac-ter widths as a printer-resident PostScript font). The screen font New York is larger than the PostScript font Times, and in the first and third lines, the printer driver (after accumulating testString1 and testString2 into one logical line) distributes the line layout error (mainly) among the spaces between words. You may even notice that the starting point of testString2 (“with ...”) has been slightly moved to the left in the process. The width of the whole line, however, is the same as on the screen.
  2932. The second line, where the LineLayoutOff comment is active, demonstrates a dramatic counterexample to the popular belief that this picture comment is here to assure precise positioning of text. It seems the opposite is true, and the LaserWriter driver has deliberately ignored the MoveTo(x0+w,y) instruction! What we would have expected is this:
  2933. Figure 2—Desired result of the LineLayoutOff comment
  2934. The attentive reader already knows the explanation. As mentioned earlier, we must break the LaserWriter driver’s heuristic line accumulation algorithm before drawing testString2. Short of adequate documentation, developers have found out that a FlushGrafPortState call right after the MoveTo(x0+w,y) instruction has the desired effect (see {••• (2) •••} in the code snippet given earlier). Unfortunately, it creates quite a lot of overhead in the pictures, and penalizes all printer drivers that don’t need it. A better solution is to use the StringBegin and StringEnd picture comments at the markers {••• (1) •••} and {••• (2) •••} in the code shown earlier. This indicates that testString1 is to be considered a logically independent text entity, and must not be put together with any other pieces of text coming through the textProc bottleneck. The overhead of these comments is much smaller, and they don’t affect other printer drivers at all.
  2935. The ClientLineLayout picture comment, supported by the (PostScript) LaserWriter driver, has never been documented. Its effect is rather subtle and very specific to the PostScript LaserWriter driver. Basically, it allows the application to redefine the character that absorbs the major part of the line layout error (usually the space character), and the percentages of the “major” and “minor” parts of the line layout error (usually 80 percent versus 20 percent). The “minor” part is distributed across intercharacter spacing. 
  2936. Only very ambitious page layout applications might be interested in this functio-na-lity; but then, they should rather aim at a more general scheme of line layout control that does not rely upon this very driver-specific picture comment.
  2937. The PicComment.p interface (see the Appendix) describes the TClientLLRecord structure passed through the handle parameter to the picture comment. If you want, feel free to experiment with it; we recommend, however, that you do not use this picture comment in your application. 
  2938. Caveats
  2939. •    Some older printer drivers supporting the LineLayoutOff picture comment are unable to correctly obey a subsequent LineLayoutOn picture comment.
  2940. •    Don’t forget that if you use LineLayoutOff, the burden of “WYSIWYG” is now on your shoulders, and not the printer driver’s.
  2941. •    A previous version of this Note said that setting the Font Manager’s FractEnable global to TRUE implied the effect of the LineLayoutOff picture comment. As it turned out, the statement was based on observations with a specific (older) version of the LaserWriter driver, and is not true in general. The setting of FractEnable does have some more or less subtle effects on the line layout algorithm, however; and this is quite plausible. Similarly, the results of combining the picture comments LineLayoutOff and LineLayoutOn with calls to SpaceExtra (Inside Macintosh Volume I, page 172) or CharExtra (Inside Macintosh Volume V, page 77) are sometimes unpredictable, depending on the particular printer driver.
  2942. And Finally the Good News
  2943. Given that the effect of the LineLayoutOff and LineLayoutOn comments does not require any changes in your printing code, you don’t have to worry whether or not a particular driver supports them. They are useful mainly when you’re sure you want no external assistance in computing word and character spacing for full justification, or when you need precise control over the horizontal placement of words and characters (such as in forms or tabulated text) and understand how to achieve this.
  2944. String Delimitation 
  2945. Comments:    StringBegin, StringEnd
  2946. These comments allow applications to specify the logical beginning and end of a string, possibly drawn with multiple calls to a QuickDraw text drawing routine (such as DrawChar). If this was their only raison d’être, they would have no relationship with the PostScript LaserWriter driver. But, as already let out in the preceding section on line layout, they are important to notify the printer driver that it should consider the text coming through the textProc bottleneck between StringBegin and StringEnd as an independent entity. Otherwise, the driver might continue to perform its heuristic accumulation of text drawing instructions for the same line, and defeat your text positioning intentions. Indeed, both StringBegin and StringEnd trigger the generation of PostScript instructions for drawing the text that has been accumulated in a line layout buffer, and reinitialize the internal variables for line layout computations. In other words, you need these picture comments to turn the LaserWriter driver’s line layout behavior completely off.
  2947. Polygon Comment Family
  2948. Comments:    PolyBegin, PolyEnd, PolyClose, PolySmooth, PolyIgnore
  2949. PostScript has the built-in capability of drawing cubic Bézier curve sections (see the PostScript Language Reference Manual, Second Edition, page 393). This is convenient for “smoothing” of polygons. The polygon-related picture comments have been provided to give applications easy access to this PostScript feature, with provision for including a QuickDraw approximation of the curve.
  2950. Schematically, the polygon comments are used as follows:
  2951.     PolyBeginComment;        { Put the PostScript driver into “polygon mode.” }
  2952.     ClipRect(zeroRect);        { Hide the following from QuickDraw. }
  2953.     PolyCloseComment;        { Optionally, if “closed” smoothing desired. }
  2954.     PolySmoothComment;    { Tell the driver to draw a Bézier curve. }
  2955.     DrawPolygon;        { Invisible for QuickDraw; PostScript output = curve. }
  2956.     PolyIgnoreComment;    { The driver will ignore the following line drawing. }
  2957.     SetClip(origClipRgn);    { Make it visible for QuickDraw. }
  2958.     DrawQDPolygon;        { Usually, a QuickDraw approximation of the curve. }
  2959.     PolyEndComment;        { PostScript driver resumes standard mode. }
  2960. A piece of sample code is sometimes worth more than one or two pictures; below, you’ll find both. For clarity and completeness of the exposition, we provide the coordinate definition of the polygons through arrays of Points, initialized in a preliminary DefineVertices procedure. You can enclose the PolygonDemo procedure between OpenPicture and ClosePicture calls to create a picture containing both QuickDraw and PostScript representations (see Figures 3 and 4), or you can use it as is when a printing page is open.
  2961. USES PicComments;
  2962. { See Appendix of this Note for the definition of the TPolyRec structure. }
  2963.    CONST
  2964.       kN = 4; { number of vertices for PostScript }
  2965.       kM = 6; { number of vertices for QuickDraw approximation }
  2966.    TYPE
  2967.       PointArray = array[0..0] of Point;  { range checking OFF }
  2968.       PointArrayPtr = ^PointArray;
  2969. PROCEDURE DefineVertices(VAR p,q: PointArrayPtr);
  2970.    CONST
  2971.       cx = 280;
  2972.       cy = 280;
  2973.       r0 = 200;
  2974.    BEGIN
  2975.    { The array p^ contains the control points for the Bézier curve: }
  2976.       SetPt(p^[0],cx + r0,cy);
  2977.       SetPt(p^[1],cx,cy + r0);
  2978.       SetPt(p^[2],cx - r0,cy);
  2979.       SetPt(p^[3],cx,cy - r0);
  2980.       p^[4] := p^[0];
  2981.    { q^ contains the points for a crude polygon approximation of the curve: }
  2982.       q^[0] := p^[0];
  2983.       SetPt(q^[1],cx,cy + round(0.7 * (p^[1].v - cy)));
  2984.       SetPt(q^[2],(p^[1].h + p^[2].h) DIV 2,(p^[1].v + p^[2].v) DIV 2);
  2985.       SetPt(q^[3],cx + round(0.8 * (p^[2].h - cx)),cy);
  2986.       SetPt(q^[4],q^[2].h,cy + cy - q^[2].v);
  2987.       SetPt(q^[5],q^[1].h,cy + cy - q^[1].v);
  2988.       q^[6] := q^[0];
  2989.    END;
  2990. PROCEDURE PolygonDemo;
  2991.    VAR
  2992.       p,q: PointArrayPtr;
  2993.       aPolyVerbH: TPolyVerbHdl;
  2994.       i: Integer;
  2995.       clipRgn, polyRgn: RgnHandle;
  2996.       zeroRect: Rect;
  2997.    BEGIN
  2998.       p := PointArrayPtr(NewPtr(SizeOf(Point) * (kN + 1)));
  2999.       q := PointArrayPtr(NewPtr(SizeOf(Point) * (kM + 1)));
  3000.       IF (p = NIL) OR (q = NIL) THEN DebugStr('NewPtr failed');
  3001.       DefineVertices(p,q);
  3002.       PenNormal;              { First show the standard QuickDraw polygon. }
  3003.       MoveTo(p^[0].h,p^[0].v);
  3004.       FOR i := 1 TO kN DO LineTo(p^[i].h,p^[i].v);
  3005.    
  3006.       PenSize(2,2);                { Now show the same polygon "smoothed." }
  3007.       PenPat(gray);
  3008.       { First, the PostScript representation, clipped off from QuickDraw: }
  3009.       aPolyVerbH:= TPolyVerbHdl(NewHandle(SizeOf(TPolyVerbRec)));
  3010.       IF aPolyVerbH<> NIL THEN
  3011.          WITH aPolyRecH^^ DO BEGIN        { ••• See comment 1, below. ••• }
  3012.             fPolyFrame := TRUE;
  3013.             fPolyFill  := FALSE;
  3014.             fPolyClose := FALSE;     { Compare with the result for TRUE ! }
  3015.             f3 := FALSE;
  3016.             f4 := FALSE;
  3017.             f5 := FALSE;
  3018.             f6 := FALSE;
  3019.             f7 := FALSE;
  3020.          END;
  3021.       MoveTo(p^[0].h,p^[0].v);            { ••• See comment 2, below. ••• }
  3022.       PicComment(PolyBegin,0,NIL);
  3023.    {  PicComment(PolyClose,0,NIL);  <<< Only if fPolyClose = TRUE, above! }
  3024.       PicComment(PolySmooth,SizeOf(TPolyVerbRec),Handle(aPolyVerbH));
  3025.       clipRgn := NewRgn;
  3026.       GetClip(clipRgn);
  3027.       ClipRect(zeroRect);
  3028.       FOR i := 1 TO kN DO LineTo(p^[i].h,p^[i].v);
  3029.       { Next, the -crude- QuickDraw approximation of the smoothed polygon, }
  3030.       { invisible for PostScript because of PolyIgnore: }
  3031.       SetClip(clipRgn);
  3032.       PicComment(PolyIgnore,0,NIL);
  3033.       polyRgn := NewRgn;                   { ••• See comment 3, below. ••• }
  3034.       OpenRgn;
  3035.       MoveTo(q^[0].h,q^[0].v);
  3036.       FOR i := 1 TO kM DO LineTo(q^[i].h,q^[i].v);
  3037.       CloseRgn(polyRgn);
  3038.       FrameRgn(polyRgn);         { Or FillRgn, if fPolyFill above is TRUE. }
  3039.       PicComment(PolyEnd,0,NIL);
  3040.       DisposHandle(Handle(aPolyVerbH));
  3041.       DisposeRgn(polyRgn);
  3042.       DisposPtr(Ptr(p));
  3043.       DisposPtr(Ptr(q));
  3044.    END;
  3045. Figure 3—Output on QuickDraw    Figure 4—Output on PostScript printern
  3046.                                     printer
  3047. Additional Comments and Explanations 
  3048. 1.    The fPolyFrame and fPolyFill fields of the TPolyRec record are self-explanatory. The fPolyClose flag is redundant with the PolyClose picture comment, but is included for the convenience of the LaserWriter driver. It is often misunderstood. It does not mean the polygon is being closed automatically, such as with the PostScript closepath operator; instead, it affects the shape of the smooth curve. Figure 4 shows the result for fPolyClose = FALSE; the start and end point of the polygon is distinguished. In the case of fPolyClose = TRUE, all vertices of the polygon are treated in the same manner, and the resulting curve resembles a circle (in this case).
  3049. 2.    The anonymous fields f3..f7 are reserved and should be set to zero (that is, FALSE).
  3050. 3.    The polygon is drawn at the current pen location when the PolyBegin comment is received. 
  3051. 4.    In general (and in this example), you do not need to open a region, collect the line segments in the region, and draw the polygon through FrameRgn. It is demonstrated here only to prepare you for situations where you want to fill the polygon with a pattern. You cannot open a polygon and use FillPoly, because the PostScript driver “owns” the polygon concept at this point and captures—and ignores—all line drawing between the PolyIgnore and PolyEnd comment. Regions do not interfere with polygons, however, and can be used to paint or fill the polygonal shape. 
  3052. Caveats
  3053. PostScript Level 1 has problems with very large polygons (more than about 1000 points). The workaround is to subdivide the large polygon into several smaller ones.
  3054. You cannot combine the polygon picture comments with other comments such as the rotation comments or the DashedLine comment. It’s just another limitation—no comment. 
  3055. Dashed Lines
  3056. Comments:    DashedLine, DashedStop
  3057. PostScript allows applications to draw precisely dashed lines with a given dash pattern in every direction (see the setdash operator, PostScript Language Reference Manual, Second Edition, page 500). The QuickDraw ersatz of setting the pen pattern appears to be awkward at best; the result depends very much on the direction of the line. Coding correctly dashed lines in QuickDraw is quite a hassle and rather clumsy. This is why the DashedLine and DashedStop picture comments have been provided for applications where dashed lines are important and used frequently. Applications can take advantage of these comments when printing to a PostScript printer.
  3058. The DashedLine comment tells the driver that the line drawing instructions following the comment should be dashed according to the parameters in the TDashedLine structure (see the Appendix). These parameters closely correspond to the parameters passed to the PostScript setdash operator. Only the centered field of the TDashedLine structure is not currently supported by the LaserWriter driver. It should be set to 0 in case support for centering is added in the future.
  3059. Unlike the picture comments for text rotation or even polygon smoothing, the DashedLine picture comment should not be supported by a non-PostScript driver. The only way to include representations of dashed lines with and without usage of the DashedLine picture comment is to make the following assumption: If the DashedLine comment is supported, then the printer is a PostScript printer, and the PostScriptBegin/PostScriptEnd bracket may be used to hide the QuickDraw imaging from the printer. Remember that non-PostScript printer drivers must not ignore QuickDraw imaging within PostScriptBegin and PostScriptEnd!
  3060. But we still need a trick to hide the line drawing instructions within the DashedLine – DashedStop bracket from QuickDraw. Here comes the “magic pen mode” to our rescue:
  3061. PROCEDURE DashDemo;
  3062.    CONST
  3063.       magicPen = 23; { the infamous penMode ! }
  3064.       cx = 280;
  3065.       cy = 280;
  3066.       r0 = 200;
  3067.    VAR
  3068.       dashHdl: TDashedLineHdl;
  3069.       i: Integer;
  3070.       a, rad : Extended;
  3071.    BEGIN
  3072.       PenSize(2,2);
  3073.       { First the PostScript picture comment version.  }
  3074.       { The "magic pen mode" 23 makes the line drawing invisible for QuickDraw. }
  3075.       PenMode(magicPen);
  3076.       dashHdl := TDashedLineHdl(NewHandle(SizeOf(TDashedLineRec)));
  3077.       IF dashHdl <> NIL THEN
  3078.          WITH dashHdl^^ DO BEGIN
  3079.             offset := 4;       { just for fun }
  3080.             centered := 0;     { Currently ignored - set to 0. }
  3081.             intervals[0] := 2; { number of interval specs      }
  3082.             intervals[1] := 4; { This means 4 points on ...    }
  3083.             intervals[2] := 6; { ... and 6 points off.         }
  3084.             PicComment(DashedLine, SizeOf(TDashedLineRec), Handle(dashHdl));
  3085.          END;
  3086.       rad := 3.14159 / 180;    { Conversion degrees -> radians. }
  3087.       FOR i := 0 TO 9 DO BEGIN { Draw some dashed lines. }
  3088.          a := i * 20 * rad;
  3089.          MoveTo(cx, cy);
  3090.          Line(round(r0 * cos(a)), - round(r0 * sin(a)));
  3091.       END;
  3092.       PicComment(DashedStop, 0, NIL); { That's enough! }
  3093.       DisposHandle(Handle(dashHdl));
  3094.       PenMode(srcOr);  { No magic any more. }
  3095.       { Now, the QuickDraw version. The PostScript driver must ignore it, }
  3096.       { so we enclose it between PostScriptBegin and PostScriptEnd comments.}
  3097.       PicComment(PostScriptBegin, 0, NIL);
  3098.       PenSize(2,2);
  3099.       FOR i := 0 TO 9 DO BEGIN
  3100.          MoveTo(cx,cy);
  3101.          DashedQDLine(round(r0 * cos(i * 20 * rad)),
  3102.                     - round(r0 * sin(i * 20 * rad)), dashHdl);
  3103.       END;
  3104.       PicComment(PostScriptEnd,0,NIL);
  3105.    END;
  3106. By the way: The DashedQDLine procedure is intentionally missing. It’s not precisely the subject of this Note, and thus, again, is left as a spare-time exercise for the reader.
  3107. Caveat
  3108. As mentioned earlier, the current version of the PostScript LaserWriter driver produces poor results when the DashedLine picture comment is applied to polygons. Just don’t do it!
  3109. Fractional Line Width
  3110. Comment:    SetLineWidth
  3111. QuickDraw’s design is based on a fixed 72-dpi resolution. Even when printing to a high-resolution device, the Printing Manager presents the printing grafPort, corresponding to the printable area of the page, in the integer-valued QuickDraw coordinate system with 72 dpi. Applications can use PrGeneral to image at higher device resolutions (see Inside Macintosh Volume V, page 410), but this is useful mainly for immediate printing. As a consequence, lines are usually always at least 1/72 inch wide, corresponding to the smallest pen size (1,1). For a 300-dpi device like the LaserWriter, this is disappointing.
  3112. The SetLineWidth comment allows an application to set the width of a line to any fractional value. A value of 1/4 approximately corresponds to a “hairline” on a 300 dpi LaserWriter. Curiously (but conveniently), a QuickDraw Point structure is passed in the PicComment’s data handle, the vertical coordinate representing the denominator, and the horizontal coordinate the numerator of the fraction.
  3113. Unfortunately, it is not implemented in all high-resolution QuickDraw printers; and if it is (as in the LaserWriter SC), it works differently than in PostScript printer drivers. Moreover, there is no possibility to include alternative imaging instructions in case SetLineWidth is not supported. While this is not much of a loss for hairlines, it prevents us from using the comment for fractional widths > 1, where the alternative would be to include a PenSize call with rounded arguments. Another drawback may be that, allegedly, there are plotter drivers out there that abuse this comment to set the pen color—clearly an unpleasant situation.
  3114. The difference in the implementation of the SetLineWidth comment between the PostScript LaserWriter driver and the LaserWriter SC appears as soon as SetLineWidth is used for the second time. The PostScript driver keeps an internal line scaling factor; this factor is initialized to 1.0 when a job is started. Each number passed through SetLineWidth is multiplied by the current internal scaling factor to get the effective scaling factor for the pen size. The LaserWriter SC driver, on the other hand, replaces its current scaling factor for the pen size completely by the new value passed through SetLineWidth. In order to support both implementations, you must always use an additional SetLineWidth step in order to reset the PostScript driver line width to 1.0, before scaling to the new value. 
  3115. Example
  3116. Let’s say you have set the line width to 0.25, and want to replace it by a line width of 0.5. The following two SetLineWidth comments will have the desired effect on both PostScript (PS) and QuickDraw (QD) drivers that implement the SetLineWidth comment. You don’t care about the temporary line width of 4.0 on the QuickDraw driver.
  3117.     Current Line Width    Parameter Passed    New Line Width
  3118.     PS driver    QD driver    in SetLineWidth    PS Driver    QD Driver
  3119.     0.25    0.25    4/1    1.0    4.0
  3120.     1.0    4.0    1/2    0.5    0.5
  3121. The following sample code gives the expected results only on a PostScript LaserWriter and on QuickDraw printer drivers that have the SetLineWidth comment implemented.
  3122. PROCEDURE SetNewLineWidth(oldWidth,newWidth: TLineWidth);
  3123.    VAR
  3124.       tempWidthH: TLineWidthHdl;
  3125.    BEGIN
  3126.       tempWidthH := TLineWidthHdl(NewHandle(SizeOf(TLineWidth)));
  3127.       { If tempWidthH = NIL we are screwed anyway. }
  3128.       tempWidthH^^.v := oldWidth.h;
  3129.       tempWidthH^^.h := oldWidth.v;
  3130.       PicComment(SetLineWidth,SizeOf(TLineWidth),Handle(tempWidthH));
  3131.       tempWidthH^^ := newWidth;
  3132.       PicComment(SetLineWidth,SizeOf(TLineWidth),Handle(tempWidthH));
  3133.       DisposHandle(Handle(tempWidthH));
  3134.    END;
  3135. PROCEDURE LineWidthDemo;
  3136.    CONST
  3137.       y0 = 50;  { topleft of demo }
  3138.       x0 = 50;
  3139.       d0 = 440; { length of horizontal lines }
  3140.       e0 = 5;   { distance between lines }
  3141.       kN = 5;   { number of lines }
  3142.    VAR
  3143.       oldWidth,newWidth: TLineWidth;  { actually a "Point" }
  3144.       i,j,y: Integer;
  3145.    BEGIN
  3146.       PenNormal;
  3147.       y := y0;
  3148.       SetPt(oldWidth,1,1);             { initial linewidth = 1.0 }
  3149.       FOR i := 1 TO 5 DO BEGIN
  3150.          SetPt(newWidth,4,i);
  3151.                   { want to set it to i/4 = 0.25, 0.50, 0.75 ... }
  3152.          SetNewLineWidth(oldWidth,newWidth);
  3153.          MoveTo(x0, y);
  3154.          Line(d0, 0);
  3155.          y := y + e0;
  3156.          oldWidth := newWidth;
  3157.       END;
  3158.    END;
  3159. •A Slight Imperfection
  3160. •If you experiment with the above code and draw a whole series of hairlines, you will see (depending on the values of e0 and kN) that certain lines appear thicker than they should be. This is due to rasterization effects in PostScript’s scan conversion algorithm when the line width is close to the device pixel size. In many cases, the PostScript LaserWriter driver tries to compensate for this by rounding coordinates to the 300-dpi grid. If you include SetLineWidth (or, by the way, DashedLine) picture comments, however, this does not work. PostScript Level 2 addresses this problem by means of an optional stroke adjustment feature (see the PostScript Language Reference Manual, Second Edition, pages 322 and 515).
  3161. Graphics Rotation
  3162. Comments:    RotateBegin, RotateCenter, RotateEnd
  3163. Like the picture comments discussed earlier in this Note in the section “Text Rotation,” the graphics rotation picture comments provide a method of rotating QuickDraw objects on PostScript devices. Instead of having QuickDraw perform the rotation, the printer driver rotates the entire PostScript coordinate space so that everything drawn between RotateBegin and RotateEnd will be rotated on the printer itself. This includes text drawing! You specify the center of rotation with RotateCenter and the angle of the rotation, together possibly with horizontal or vertical flipping, through the TRotation record (see the interface definitions in the Appendix).
  3164. Unlike text rotation, you must insert the RotateCenter comment and pass the relative offset to the center of rotation before you use the RotateBegin picture comment. The point passed to RotateCenter specifies the offset from the anchor point of the first object drawn after RotateBegin to the desired center of rotation. Once you set up the rotation parameters with RotateCenter and RotateBegin, you can draw the graphics objects you want to rotate.
  3165. Bad news: In order to include a QuickDraw representation of the rotated objects in case the rotation comments are not supported, we have to assume (again) that only PostScript drivers implement these comments. The only way to hide the QuickDraw substitute from the driver is to surround it by PostScriptBegin and PostScriptEnd comments; and, similarly to the DashedLine comment, we need to use the “magic pen mode” (23) to hide the unrotated drawing between RotateBegin and RotateEnd from QuickDraw. The following sample demonstrates this:
  3166. PROCEDURE QDRotatedRect(r: Rect; ctr: Point; angle: Integer);
  3167.    BEGIN
  3168.       { An exercise again - this one is easy ...             }
  3169.       { Rotates the four points of the rectangle by "angle"  }
  3170.       { around the center obtained by adding the point "ctr" }
  3171.       { as offset to r.topLeft, and draws the rotated Rect.  }
  3172.    END;
  3173. PROCEDURE PSRotatedRect(r: Rect; offset: Point; angle: Integer);
  3174. { Does the rectangle rotation for the PostScript LaserWriter driver. }
  3175. { Uses the RotateCenter, RotateBegin and RotateEnd picture comments, }
  3176. { and the "magic" pen mode 23 to hide the drawing from QuickDraw.    }
  3177.    CONST
  3178.       magicPen = 23;
  3179.    VAR
  3180.       rInfo: TRotationHdl;
  3181.       rCenter: TCenterHdl;
  3182.       oldPenMode: Integer;
  3183.    BEGIN
  3184.       rInfo := TRotationHdl(NewHandle(SizeOf(TRotationRec)));
  3185.       rCenter := TCenterHdl(NewHandle(SizeOf(TCenterRec)));
  3186.       IF (rInfo = NIL) OR (rCenter = NIL) THEN DebugStr('NewHandle failed');
  3187.       WITH rInfo^^ DO BEGIN
  3188.          rFlip := 0;
  3189.          rAngle := - angle;
  3190.          rAngleFixed := BitShift(LongInt(rAngle),16);
  3191.       END;
  3192.       WITH rCenter^^ DO BEGIN
  3193.          x := Long2Fix(offset.h);
  3194.          y := Long2Fix(offset.v);
  3195.       END;
  3196.       MoveTo(r.left,r.top);
  3197.       FlushGrafPortState;
  3198.       PicComment(RotateCenter,SizeOf(TCenterRec),Handle(rCenter));
  3199.       PicComment(RotateBegin,SizeOf(TRotationRec),Handle(rInfo));
  3200.       oldPenMode := thePort^.pnMode;
  3201.       PenMode(magicPen);
  3202.       FrameRect(r);
  3203.       PenMode(oldPenMode);
  3204.       PicComment(RotateEnd,0,NIL);
  3205.       DisposeHandle(Handle(rInfo));
  3206.       DisposeHandle(Handle(rCenter));
  3207.    END;
  3208. PROCEDURE RotateDemo;
  3209.    CONST
  3210.       angle = 30;
  3211.    VAR
  3212.       spinRect: Rect;
  3213.       delta: Point;
  3214.    BEGIN
  3215.       SetRect(spinRect,100,100,300,200);
  3216.       WITH spinRect DO SetPt(delta,(right - left) DIV 2,(bottom - top) DIV 2);
  3217.       PenSize(2,2);
  3218.       PenPat(ltGray);
  3219.       FrameRect(spinRect); { show the unrotated square }
  3220.       PenNormal;
  3221.       PSRotatedRect(spinRect,delta,angle);
  3222.  { QuickDraw equivalent of the rotated object, hidden from PostScript driver  }
  3223.  { because of PostScriptBegin and PostScriptEnd }
  3224.       PicComment(PostScriptBegin,0,NIL);
  3225.       QDRotatedRect(spinRect,delta,angle);
  3226.       PicComment(PostScriptEnd,0,NIL);
  3227.    END;
  3228. PostScript Comments
  3229. Comments:    PostScriptBegin, PSBeginNoSave, PostScriptEnd, PostScriptHandle
  3230. The PostScript comments tell the picture interpreter (usually the LaserWriter driver) that the application is going to communicate with the LaserWriter directly using PostScript code instead of QuickDraw. All QuickDraw drawing instructions between the PostScriptBegin and PostScriptEnd picture comments are ignored. The driver sends the PostScript text contained in the PostScriptHandle data to the printer with no preprocessing and no error checking. When the application is finished sending PostScript, the PostScriptEnd comment tells the printer driver to resume normal QuickDraw mode. The driver uses the PostScript save and restore operators to preserve the state of the PostScript interpreter across the section enclosed by PostScriptBegin and PostScriptEnd. Some applications do not want to restore the previous state of the PostScript interpreter after including their PostScript code; for these situations, the PSBeginNoSave comment is a replacement for PostScriptBegin that does not preserve the state. Clearly, this comment should be used with extreme caution.
  3231. Some state information may be stored in global variables, so nesting PostScriptBegin (or PSBeginNoSave) and PostScriptEnd comments is not allowed.
  3232. The PostScriptHandle comment gives developers direct access to PostScript from applications. Instead of having the LaserWriter driver convert QuickDraw calls into the corresponding PostScript code, the application can generate its own PostScript, and transmit it to the printer or include it in a picture through the data handle of the PicComment procedure. The handle contains pure ASCII text; the valid length of the data is specified in the PicComment’s size parameter. Don’t forget to terminate the PostScript text at least with a space character, or better with a carriage return (ASCII $0D), so that it is separated from the following PostScript instructions (either yours, or the printer driver’s).
  3233. You must still use PostScriptBegin (or PSBeginNoSave) and PostScriptEnd around PostScriptHandle comments or the LaserWriter driver will not properly save and restore the PostScript drawing environment. 
  3234. As with all picture comments, the handle you pass belongs to you and you must dispose of it when you’re finished with it.
  3235. PROCEDURE PostScriptLine(s: Str255);
  3236. { A utility procedure to transmit a string of PostScript code through }
  3237. { the PostScriptHandle picture comment to the PostScript printer.     }
  3238. { It should be called only between PostScriptBegin and PostScriptEnd  }
  3239. { picture comments. }
  3240.    VAR
  3241.       h: Handle;
  3242.    BEGIN
  3243.       h := NewHandle(256);
  3244.       IF h = NIL THEN DebugStr('NewHandle failed');
  3245.       BlockMove(@s[1],h^, Length(s));
  3246.       PicComment(PostScriptHandle, Length(s), h);
  3247.       h^^ := 13;
  3248.       PicComment(PostScriptHandle, 1, h); { add a carriage return }
  3249.       DisposeHandle(h);
  3250.    END;
  3251. PROCEDURE PostScriptComments;
  3252.    BEGIN
  3253.       { First, the simple example: }
  3254.       PicComment(PostScriptBegin,0,NIL);
  3255.       PostScriptLine('100 100 moveto 0 100 rlineto 100 0 rlineto ');
  3256.       PostScriptLine('0 -100 rlineto -100 0 rlineto');
  3257.       PostScriptLine('stroke');
  3258.       MoveTo(30,30);
  3259.       DrawString('This text does not appear on PostScript devices');
  3260.       PicComment(PostScriptEnd,0,NIL);
  3261.       { Now, a new PostScript definition you want to keep in the     }
  3262.       { userdict. If you used PostScriptBegin, the definition would  }
  3263.       { be lost when PostScriptEnd is encountered, because the state }
  3264.       { previous to the PostScriptBegin comment would be restored.   }
  3265.       PicComment(PSBeginNoSave,0,NIL);
  3266.       PostScriptLine('userdict begin');
  3267.       PostScriptLine('/myFrameRect {');
  3268.       PostScriptLine('250 250 moveto 0 100 rlineto');
  3269.       PostScriptLine('200 0 rlineto 0 -100 rlineto -200 0 rlineto ');
  3270.       PostScriptLine('stroke } def');
  3271.       PostScriptLine('end');
  3272.       PicComment(PostScriptEnd,0,NIL);
  3273.       { Let's test to see if the definition from above is still avail-}
  3274.       { able. This assumes that no font downloading has occurred.     }
  3275.       PicComment(PostScriptBegin,0,NIL);
  3276.       PostScriptLine('//userdict /myFrameRect get exec ');
  3277.       PicComment(PostScriptEnd,0,NIL);
  3278.    END;
  3279. Caveat
  3280. If you choose to use PostScript directly in your pictures, be very careful not to make assumptions about Apple’s "md" dictionary (essentially the contents of the former LaserPrep file). Otherwise, your pictures will not print correctly with future versions of the PostScript LaserWriter driver. Also, be aware of compatibility problems within the PostScript world, and watch out for printers with PostScript Level 1 and PostScript Level 2 interpreters, and “PostScript-compatible” printers (PostScript clones).
  3281. FormsPrinting Picture Comments
  3282. Comments:    FormsPrinting, EndFormsPrinting
  3283. The FormsPrinting comment tells the PostScript LaserWriter driver not to clear its page buffer after printing a page. EndFormsPrinting turns this mode off. When the page is completed, the application must erase the areas that need to be updated and draw the new information. The graphics that make up the form are drawn only once per page, which may improve performance. Currently, you need to write special printing code for the PostScript LaserWriter driver if you want to use this comment. 
  3284. (More or Less) Obsolete PostScript Picture Comments
  3285. Comments:    SetGrayLevel,
  3286.     TextIsPostScript, ResourcePS, PostScriptFile
  3287. The SetGrayLevel picture comment was designed to provide access to the PostScript setgray operator while still drawing with QuickDraw in black-and-white mode. In practice, this turned out to be not so useful, however. For most drawing operations, the printer driver sets the gray level to match the foreground color currently stored in the printing grafPort, and the effect of the SetGrayLevel comment is often unpredictable. If direct access to the PostScript setgray operator seems nevertheless desirable, it is easy to include the instruction in a PostScriptHandle comment.
  3288. The TextIsPostScript picture comment takes all the text coming through standard QuickDraw text drawing calls (DrawChar, DrawString, DrawText, and anything else that eventually calls the StdText bottleneck), and interprets it as a PostScript program. There is no good reason to use this picture comment, but there is one important reason not to use it: Printer drivers that do not deal with the TextIsPostScript comment will print the PostScript text instead of interpreting it! If you need to transmit pure PostScript code directly to a printer that understands it, use the PostScriptHandle comment, and include a QuickDraw representation for all other printer drivers.
  3289. The ResourcePS picture comment loads PostScript code from a specified resource. The resource file is expected to be open at the time that the ResourcePS comment is used. Under background printing, there are no guarantees the file will still be open when the Printing Manager needs it. For this reason alone, you should forget about this comment. If you want to keep PostScript instructions in a resource, it is easy to write a small routine that loads the resources and sends their contents using the PostScriptHandle comment described earlier in this Note.
  3290. PostScriptFile has the same problems as ResourcePS described above. Basically, the Printing Manager cannot guarantee that the file will be available when it’s needed.
  3291. Appendix: Pascal Interface for Picture Comments
  3292. (File PicComments.p)
  3293. CONST
  3294.    TextBegin = 150;
  3295.    TextEnd = 151;
  3296.    StringBegin = 152;
  3297.    StringEnd = 153;
  3298.    TextCenter = 154;
  3299.    LineLayoutOff = 155;
  3300.    LineLayoutOn = 156;
  3301.    ClientLineLayout = 157;
  3302.    PolyBegin = 160;
  3303.    PolyEnd = 161;
  3304.    PolyIgnore = 163;
  3305.    PolySmooth = 164;
  3306.    PolyClose = 165;
  3307.    DashedLine = 180;
  3308.    DashedStop = 181;
  3309.    SetLineWidth = 182;
  3310.    PostScriptBegin = 190;
  3311.    PostScriptEnd = 191;
  3312.    PostScriptHandle = 192;
  3313.    PostScriptFile = 193;
  3314.    TextIsPostScript = 194;
  3315.    ResourcePS = 195;
  3316.    PSBeginNoSave = 196;
  3317.    SetGrayLevel = 197;
  3318.    RotateBegin = 200;
  3319.    RotateEnd = 201;
  3320.    RotateCenter = 202;
  3321.    FormsPrinting = 210;
  3322.    EndFormsPrinting = 211;
  3323.   
  3324.    tJusNone = 0;           { values for the tJus field of the TTxtPicRec record }
  3325.    tJusLeft = 1;
  3326.    tJusCenter = 2;
  3327.    tJusRight = 3;
  3328.    tJusFull = 4;
  3329.    
  3330.    tFlipNone = 0;         { values for the tFlip field of the TTxtPicRec record }
  3331.    tFlipHorizontal = 1;
  3332.    tFlipVertical = 2;
  3333. TYPE
  3334.    TTxtPicHdl = ^TTxtPicPtr;
  3335.    TTxtPicPtr = ^TTxtPicRec;
  3336.    TTxtPicRec = PACKED RECORD
  3337.                    tJus  : Byte;
  3338.                    tFlip : Byte; 
  3339.                    tAngle: Integer;     { clockwise rotation in degrees 0..360 }
  3340.                    tLine : Byte;        { Unused/Ignored }
  3341.                    tCmnt : Byte;        { reserved }
  3342.                    tAngleFixed: Fixed;  { same as "tAngle" in Fixed precision  }
  3343.                END; { TTxtPicRec }
  3344.    TRotationHdl = ^TRotationPtr;
  3345.    TRotationPtr = ^TRotation;
  3346.    TRotationRec = RECORD
  3347.                     rFlip: Integer;
  3348.                     rAngle: Integer;    { clockwise rotation in degrees 0..360 }
  3349.                     rAngleFixed: Fixed; { same as "rAngle" in Fixed precision  }
  3350.                  END; { TRotationRec }
  3351.    TCenterHdl = ^TCenterPtr;
  3352.    TCenterPtr = ^TCenter;
  3353.    TCenterRec = RECORD  {offset from current pen location to center of rotation}
  3354.                    y: Fixed;
  3355.                    x: Fixed;
  3356.                 END; { TCenterRec }
  3357.    TPolyVerbHdl = ^TPolyVerbPtr;
  3358.    TPolyVerbPtr = ^TPolyVerbRec;
  3359.    TPolyVerbRec = PACKED RECORD
  3360.                      f7,f6,f5,f4, f3,     { reserved }
  3361.                      fPolyClose,          { TRUE = smoothing across endpoint.}
  3362.                      fPolyFill,           { TRUE = Polygon should be filled. }
  3363.                      fPolyFrame: BOOLEAN; { TRUE = Polygon should be framed. }
  3364.                   END;
  3365.    TDashedLineHdl = ^TDashedLinePtr;
  3366.    TDashedLinePtr = ^TDashedLineRec;
  3367.    TDashedLineRec = PACKED RECORD
  3368.                        offset   : SignedByte;  { offset into pattern for }                                   { first dash              }
  3369.                        centered : SignedByte;  { (Ignored)               }
  3370.                        intervals: ARRAY [0..5] { Array of dash intervals }
  3371.                                   OF SignedByte; { intervals[0] = number }
  3372.                     END;                         { of interval specs.    }
  3373.    TLineWidthHdl = ^TLineWidthPtr;
  3374.    TLineWidthPtr = ^TLineWidth;
  3375.    TLineWidth    = Point;  { v = numerator, h = denominator. }
  3376.    TClientLLHdl = ^TClientLLPtr;  { used in the ClientLineLayout picture comment }
  3377.    TClientLLPtr = ^TClientLLRec;
  3378.    TClientLLRec = RECORD
  3379.                      chCount : Integer;  { Apply for so many characters. }
  3380.                      major   : Fixed;    { percentage of line layout error to be }
  3381.                                          { distributed among space characters.   }
  3382.                      spcChar : Integer;  { code of character that is to absorb   }
  3383.                                          { the "major" line layout error         }
  3384.                      minor   : Fixed;    { percentage of intercharacter distrib. }
  3385.                      ulLength: Fixed;    { underline length.                     }
  3386.                   END;
  3387. Further Reference:
  3388. •    PostScript Language Reference Manual, Adobe Systems Inc.
  3389. •    Inside Macintosh, Volumes II, V, and VI
  3390. •    LaserWriter Reference Manual, Addison-Wesley
  3391. •    Macintosh Technical Note M.IM.AppPictComments —    
  3392.         Every Picture [Comment] Tells Its Story, Don’t It?
  3393. •    Macintosh Technical Note M.IM.PictAndPrinting —
  3394.         Pictures and the Printing Manager
  3395. •    develop Issue 3, “Meet PrGeneral” by Pete “Luke” Alexander
  3396. Adobe is a trademark of Adobe Systems Incorporated.
  3397. PostScript is a registered trademark of Adobe Systems Incorporated.
  3398. Every Picture [Comment] Tells Its Story, Don’t It?
  3399. Imaging    M.IM.AppPictComments
  3400. Revised by:         March 1988
  3401. Written by:    Rick Blair    November 1987
  3402. Application-specific picture comment conflict and registration is addressed, along with Developer Technical Support’s method for solving it.
  3403. I will assume that the nature and usefulness of picture comments are already well known. The problem I am addressing is that, as it stands, developers must register their comments with us (Developer Technical Support) or run the risk of using the same comments as those used by Apple or within another third party product.
  3404. The idea here is to provide a “metacomment” which will contain information about which application owns the comment as well as the comment itself:
  3405. ApplicationComment (long comment)    kind = 100  size = n + 6
  3406.     data = application signature (i.e. 'MPNT' for MacPaint) = 4 bytes
  3407.            application “local” kind = 2 bytes
  3408.            comment data = n bytes
  3409. In this way each comment may be specific to an application. It is still up to a developer to publish information about the comments they have defined if they wish them to be understood and used by other programs.
  3410. Previously assigned and registered comments will still be valid. This means that those  defined for the LaserWriter or MacDraw, for instance, will retain their normal meaning.
  3411. Suppose your application (creator = 'MYAP') wanted to define a comment. The appearance of the comment would be as follows (assuming you chose 128 to be the “local” kind for the comment):
  3412.     kind = 100; data = 'MYAP' [4 bytes] + 128 [2 bytes] + additional data
  3413. Further Reference:
  3414. •    QuickDraw
  3415. •    Technical Note M.IM.PictComments — 
  3416.         Optimizing for the LaserWriter—Picture Comments
  3417. QuickDraw’s Internal Picture Definition
  3418. Imagining    M.IM.PictureOpcodes
  3419. Revised by:    Rick Blair    November 1986
  3420.             March 1988
  3421. Written by:    Ginger Jenigan    April 1985
  3422. This technical note describes the internal format of the QuickDraw picture data structure. This revision corrects some errors in the opcode descriptions and provides some examples.
  3423. This technical note describes the internal definition of the QuickDraw picture. The information given here only applies to QuickDraw picture format version 1.0 (which is always created by Macintoshes without Color QuickDraw). Picture format version 2.0 is documented in the Color QuickDraw chapter of Inside Macintosh. This information should not be used to write your own picture bottleneck procedures; if we add new objects to the picture definition, your program will not be able to operate on pictures created using standard QuickDraw. Your program will not know the size of the new objects and will, therefore, not be able to proceed past the new objects. (What this ultimately means is that you can’t process a new picture with an old bottleneck proc.)
  3424. Terms
  3425. An opcode is a number that DrawPicture uses to determine what object to draw or what mode to change for subsequent drawing. The following list gives the opcode, the name of the object (or mode), the associated data, and the total size of the opcode and data. To better interpret the sizes, please refer to page I-91 of the Using Assembly Language chapter of Inside Macintosh. For types not described there, here is a quick list:
  3426.     opcode    byte
  3427.     mode        word
  3428.     point        4 bytes
  3429.     0..255    byte
  3430.     –128..127    signed byte
  3431.     rect        8 bytes
  3432.     poly        10+ bytes (starts with word size for poly (incl. size word)
  3433.     region        10+ bytes (starts with word size for region (incl. size word)
  3434.     fixed point    long
  3435.     pattern    8 bytes
  3436.     rowbytes    word (always even)
  3437.     bit data    rowbytes * (bounds.bottom - bounds.top) bytes
  3438. Each picture definition begins with a picsize (word), then a picframe (rect), and then the picture definition, which consists of a combination of the following opcodes:
  3439. Opcode        Name        Additional Data                Total Size (bytes)
  3440. 00        NOP        none                    1
  3441. 01        clipRgn    rgn                    1+rgn
  3442. 02        bkPat        pattern                    9
  3443. 03        txFont        font (word)                3
  3444. 04        txFace        face (byte)                2
  3445. 05         txMode        mode (word)                3
  3446. 06        spExtra        extra (fixed point)            5
  3447. 07        pnSize        pnSize (point)                5
  3448. 08        pnMode    mode (word)                3
  3449. 09        pnPat        pattern                    9
  3450. 0A        thePat        pattern                    9
  3451. 0B        ovSize        point                    5
  3452. 0C        origin        dh, dv (words)                5
  3453. 0D        txSize        size (word)                3
  3454. 0E        fgColor        color (long)                5
  3455. 0F        bkColor    color (long)                5
  3456. 10        txRatio        numer (point), denom (point)        9
  3457. 11        picVersion    version (byte)    2
  3458. 20         line        pnLoc ( point ), newPt ( point )        9
  3459. 21        line from    newPt ( point )                5
  3460. 22        short line    pnLoc ( point ); dh, dv (-128..127)        7
  3461. 23        short line from    dh, dv (-128..127)            3
  3462. 28         long text    txLoc ( point ), count (0..255), text    6+text
  3463. 29        DH text    dh (0..255), count (0..255), text        3+text
  3464. 2A        DV text    dv (0..255), count (0..255), text        3+text
  3465. 2B        DHDV text    dh, dv (0..255), count (0..255), text    4+text
  3466. 30         frameRect    rect                    9
  3467. 31        paintRect     rect                    9
  3468. 32        eraseRect     rect                    9
  3469. 33        invertRect     rect                    9
  3470. 34        fillRect     rect                    9
  3471. 38         frameSameRect    rect                    1
  3472. 39        paintSameRect     rect                    1
  3473. 3A        eraseSameRect     rect                    1
  3474. 3B        invertSameRect     rect                    1
  3475. 3C        fillSameRect     rect                    1
  3476. 40         frameRRect    rect ( ovalwidth, height; see 1, below )    9
  3477. 41        paintRRect     rect ( ovalwidth, height; see 1, below )    9
  3478. 42        eraseRRect     rect ( ovalwidth, height; see 1, below )    9
  3479. 43        invertRRect         rect ( ovalwidth, height; see 1, below )    9
  3480. 44        fillRRect         rect ( ovalwidth, height; see 1, below )    9
  3481. 48         frameSameRRect    rect                    1
  3482. 49        paintSameRRect     rect                    1
  3483. Opcode (cont.)    Name             Additional Data            Total Size (bytes)
  3484. 4A        eraseSameRRect     rect                    1
  3485. 4B        invertSameRRect     rect                    1
  3486. 4C        fillSameRRect         rect                    1
  3487. 50         frameOval        rect                    9
  3488. 51        paintOval         rect                    9
  3489. 52        eraseOval        rect                    9
  3490. 53        invertOval         rect                    9
  3491. 54        fillOval         rect                    9
  3492. 58         frameSameOval        rect                    1
  3493. 59        paintSameOval         rect                    1
  3494. 5A        eraseSameOval         rect                    1
  3495. 5B        invertSameOval        rect                    1
  3496. 5C        fillSameOval         rect                    1
  3497. 60         frameArc        rect, startAngle, arcAngle            13
  3498. 61        paintArc         rect, startAngle, arcAngle            13
  3499. 62        eraseArc        rect, startAngle, arcAngle            13
  3500. 63        invertArc         rect, startAngle, arcAngle            13
  3501. 64        fillArc             rect, startAngle, arcAngle            13
  3502. 68         frameSameArc        startAngle, arcAngle            5
  3503. 69        paintSameArc         startAngle, arcAngle            5
  3504. 6A        eraseSameArc         startAngle, arcAngle            5
  3505. 6B        invertSameArc        startAngle, arcAngle            5
  3506. 6C        fillSameArc         startAngle, arcAngle            5
  3507. 70        framePoly        poly                    1+poly
  3508. 71        paintPoly        poly                    1+poly
  3509. 72        erasePoly         poly                    1+poly
  3510. 73        invertPoly         poly                    1+poly
  3511. 74        fillPoly         poly                    1+poly
  3512.     
  3513. 78        frameSamePoly         (not yet implemented—same as 70, etc.)    1
  3514. 79        paintSamePoly         (not yet implemented)            1
  3515. 7A        eraseSamePoly         (not yet implemented)            1
  3516. 7B        invertSamePoly        (not yet implemented)            1
  3517. 7C        fillSamePoly        (not yet implemented)            1
  3518. 80        frameRgn        rgn                    1+rgn
  3519. 81        paintRgn        rgn                    1+rgn
  3520. 82        eraseRgn         rgn                    1+rgn
  3521. 83        invertRgn         rgn                    1+rgn
  3522. 84        fillRgn         rgn                    1+rgn
  3523. 88        frameSameRgn         (not yet implemented—same as 80, etc.)    1
  3524. 89        paintSameRgn         (not yet implemented)            1
  3525. 8A        eraseSameRgn         (not yet implemented)            1
  3526. 8B        invertSameRgn        (not yet implemented)            1
  3527. 8C        fillSameRgn        (not yet implemented)            1 
  3528. 90        BitsRect        rowBytes, bounds, srcRect, dstRect, mode,    29+unpacked
  3529.                     unpacked bitData             bitData
  3530. Opcode (cont.)    Name             Additional Data            Total Size (bytes)
  3531. 91        BitsRgn        rowBytes, bounds, srcRect, dstRect, mode,    29+rgn+
  3532.                     maskRgn, unpacked bitData        bitData
  3533. 98        PackBitsRect        rowBytes, bounds, srcRect, dstRect, mode,    29+packed
  3534.                     packed bitData for each row        bitData
  3535. 99        PackBitsRgn        rowBytes, bounds, srcRect, dstRect, mode,    29+rgn+
  3536.                     maskRgn, packed bitData for each row    packed bitData
  3537. A0        shortComment        kind(word)                3
  3538. A1        longComment        kind(word), size(word), data        5+data
  3539. FF        EndOfPicture        none                    1
  3540. Notes
  3541. Rounded-corner rectangles use the setting of the ovSize point (see opcode $0B, above).
  3542. OpenPicture and DrawPicture set up a default set of port characteristics when they start. When drawing occurs, if the user’s settings don’t match the defaults, mode opcodes are generated. This is why there is usually a clipRgn code after the picVersion: the default clip region is an empty rectangle.
  3543. The only savings that the “same” opcodes achieve under the current implementation is for rectangles. DrawPicture keeps track of the last rectangle used and if a “same” opcode is encountered that requests a rectangle, the last rect. will be used (and no rectangle will appear in the opcode’s data).
  3544. This last section contains some Pascal program fragments that generate pictures. Each section starts out with the picture itself (yes, they’re dull) followed by the code to create and draw it, and concludes with a commented hex dump of the picture.
  3545.     {variables used in all examples}
  3546.     VAR
  3547.         err:     OSErr;
  3548.         ph:      PicHandle;
  3549.         h:       Handle;
  3550.         r:       Rect;
  3551.         smallr:  Rect;
  3552.         orgr:    Rect;
  3553.         pstate:  PenState; {are they in the Rose Bowl, or the state pen?}
  3554. I.    {Rounded-corner rectangle}
  3555.     SetRect(r, 20, 10, 120, 175);
  3556.     ClipRect(myWindow^.portRect);
  3557.     ph := OpenPicture(r);
  3558.     FrameRoundRect (r, 5, 4); {r,width,height}
  3559.     ClosePicture;
  3560.     DrawPicture(ph, r);
  3561. 'PICT' (1)  0026 {size}  000A 0014 00AF 0078 {picFrame}
  3562.     1101 {version 1}  01 000A 0000 0000 00FA 0190 {clipRgn — 10 byte region}
  3563.     0B 0004 0005 {ovSize point}  40 000A 0014 00AF 0078 {frameRRect
  3564.     rectangle}
  3565.     FF {fin} 
  3566. _______________________________________________________________________________________________
  3567. II.    {Overpainted arc}
  3568.     GetPenState(pstate); {save}
  3569.     SetRect(r, 20, 10, 120, 175);
  3570.     ClipRect(myWindow^.portRect);
  3571.     ph := OpenPicture(r);
  3572.     PaintArc(r, 3, 45); {r,startangle,endangle}
  3573.     PenPat(gray);
  3574.     PenMode(patXor); {turn the black to gray}
  3575.     PaintArc(r, 3, 45); {r,startangle,endangle}
  3576.     ClosePicture;
  3577.     SetPenState(pstate); {restore}
  3578.     DrawPicture(ph, r);
  3579. data 'PICT' (2)  0036 {size}  000A 0014 00AF 0078 {picFrame}
  3580.     1101 {version 1}  01 000A 0000 0000 00FA 0190 {clipRgn — 10 byte region}
  3581.     61 000A 0014 00AF 0078 0003 002D {paintArc rectangle,startangle,endangle}
  3582.     08 000A {pnMode patXor — note that the pnMode comes before the pnPat}
  3583.     09 AA55 AA55 AA55 AA55 {pnPat gray}
  3584.     69 0003 002D {paintSameArc startangle,endangle}
  3585.     FF {fin} 
  3586. III.    {CopyBits nopack, norgn, nowoman, nocry}
  3587.     GetPenState(pstate);
  3588.     SetRect(r, 20, 10, 120, 175);
  3589.     SetRect(smallr, 20, 10, 25, 15);
  3590.     SetRect(orgr, 0, 0, 30, 20);
  3591.     ClipRect(myWindow^.portRect);
  3592.     ph := OpenPicture(r);
  3593.     PaintRect(r);
  3594.     CopyBits (myWindow^.portBits, myWindow^.portBits,
  3595.                  smallr, orgr, notSrcXor, NIL); 
  3596.     {note: result BitMap is 8 bits wide instead of the 5 specified by     smallr}
  3597.     ClosePicture;
  3598.     SetPenState(pstate); {restore the port's original pen state}
  3599.     DrawPicture(ph, r);
  3600. data 'PICT' (3)  0048 {size}  000A 0014 00AF 0078 {picFrame}
  3601.     1101 {version 1}  01 000A 0000 0000 00FA 0190 {clipRgn — 10 byte region}
  3602.     31 000A 0014 00AF 0078 {paintRect rectangle}
  3603.     90 0002 000A 0014 000F 001C {BitsRect rowbytes bounds (note that bounds                         is wider than smallr)}
  3604.     000A 0014 000F 0019 {srcRect}
  3605.     0000 0000 0014 001E {dstRect}
  3606.     00 06 {mode=notSrcXor}
  3607.     0000 0000 0000 0000 0000 {5 rows of empty bitmap (we copied from a
  3608.                                 still-blank window)}
  3609.     FF {fin}
  3610. Further Reference:
  3611. •    QuickDraw
  3612. •    Color QuickDraw
  3613. •    Using Assembly Language
  3614. •    Technical Note #59—Pictures and Clip Regions
  3615. Picture Utility Q&As
  3616. Imaging    M.IM.PictUtil.Q&As
  3617. Revised by:    Developer Support Center    October 1992
  3618. Written by:    Developer Support Center    October 1990
  3619. This Technical Note contains a collection of Q&As relating to a specific topic—questions you’ve sent the Developer Support Center (DSC) along with answers from the DSC engineers. While DSC engineers have checked the Q&A content for accuracy, the Q&A Technical Notes don’t have the editing and organization of other Technical Notes. The Q&A function is to get new technical information and updates to you quickly, saving the polish for when the information migrates into reference manuals.
  3620. Q&As are now included with Technical Notes to make access to technical updates easier for you. If you have comments or suggestions about Q&A content or distribution, please let us know by sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical questions about Q&A content to DEVSUPPORT for resolution.
  3621. New Q&As and Q&As revised this month are marked with a bar in the side margin.
  3622. GetPictInfo and QuickTime compressed PICT files
  3623. Written:    2/24/92
  3624. Last reviewed:    8/1/92
  3625. Is it my imagination, or does GetPictInfo return a bit depth of 1 on QuickTime compressed PICT files?
  3626. ___
  3627. Yep! I think this is what happens: The PUP (Picture Utility Package) does not know of the QuickTime Compressed Pixmap opcode (0x8200) and it just skips over the opcode’s data; then it finds the PacksBitRect opcode containing the black-and-white pseudo-alert that you get when you draw the picture in a machine that does not have QuickTime installed, and this is what GetPictInfo reports back.
  3628. Trivia: when QuickTime is installed it displays the compressed image and then ignores the following PacksBitRect since QuickTime knows it is only the b&w warning.
  3629. NewPalette doesn’t use CTab2Palette to create a palette
  3630. Written:    3/12/92
  3631. Last reviewed:    8/1/92
  3632. I am using the Picture Utilities package to extract the color table from a picture. After getting the color table, I use NewPalette to construct a palette from the color table (usage = tolerant, tolerance = 0). After doing this, the RGB values in the palette don’t always exactly match the RGB values in the source color table, causing my program to fail. If I use NewPalette without a source color table, and then use CTab2Palette to copy the colors over (again with usage = tolerant, tolerance = 0), the colors match exactly.
  3633. ___
  3634. It turns out that NewPalette does not use CTab2Palette, but copies the RGB fields in a strange fashion that is causing the problems you are seeing.
  3635. NewPalette copies the high byte in each color table RGB entry into the high byte, as well as the low byte of the corresponding palette entry. Thus, if the color table entry for red was $F000, it becomes $F0F0. This of course makes no difference to QuickDraw since the low byte is not displayed, but if your program expects the low byte to match, then that is where your problem exists.
  3636. It is unfortunate that CTab2Palette is different. It turns out that CTab2Palette does not copy the high byte into the low byte unless the pmAnimated bit is set in the usage.
  3637. So, the best solution for your code is not to compare the entire RGB value when comparing colors, but rather to compare the high byte of each RGB component separately. If this is not possible, the next best solution is for you to go ahead and use the workaround that you’ve already discovered with CTab2Palette.
  3638. It’s unlikely that the the Palette Manager is going to change in the future for something like this. In fact, we would almost call it a “feature” since other developers may even depend on it.
  3639. Spooling PixMaps to disk
  3640. Written:    6/10/91
  3641. Last reviewed:    10/22/91
  3642. Do you have sample code for spooling PixMaps to disk in PICT format? Should I write the PICT opcodes to the file myself?
  3643. ___
  3644. Apple recommends that you do not try to write the PICT opcodes yourself. Instead, replace the PutPicProc bottleneck proc, as shown in the Color QuickDraw chapter of Inside Macintosh Volume V on page V-89.
  3645. Two additional samples can be found in the sample code contained in the Developer CDs. Look for: “Tools & Apps: Graphics and Imaging: PICT Stuff.” One is a program and the other is an FKEY; both dump the main screen to disk as a PICT. The FKEY is a more complete sample in the sense that it works in black and white as well as Macintosh color computers, but the other is a smaller and simpler sample.
  3646. Getting the color usage from a picture under System 6
  3647. Written:    6/8/92
  3648. Last reviewed:    9/15/92
  3649. Do you know how I can obtain the color table of a picture when using a system version that happens to be less than 7.0? The Picture Utilites package seems to be only implemented in System 7.0.
  3650. ___
  3651. You’re correct; the Picture Utilities package is implemented only under System 7. However, it’s possible to write code to duplicate its functionality under System 6. Basically, what you want to do is parse a picture, looking at the colors used for the different objects. How you deal with the colors is up to you.
  3652. What you do is replace the QuickDraw bottlenecks in a GrafPort with procedures of your own; in all the bottlenecks for QuickDraw primitives, you can just record the current color as having been used for an object. When you get a StdBits opcode, you’ll have to parse the pixmaps, looking through the image and recording all the colors used. As a shortcut, you could just record all the colors in the color table of the pixmap, if it's an indexed pixel image. After collecting this list of colors and any information on how often they are used, it’s up to you to boil this down into useful information, depending on how you want to use it.
  3653. Pictures and Clip Regions
  3654. Imaging    M.IM.PictClipRegions
  3655. Revised by:         March 1988
  3656. Written by:    Jennifer Jernigan    January 1986
  3657. This note describes a problem that affects creation of QuickDraw pictures.
  3658. When a GrafPort is created, the fields in the GrafPort are given default values; one of these is the clip region, which is set to the rectangle (–32767, –32767, 32767, 32767). If you create a picture, then call DrawPicture with a destination rectangle that is not the same size as the picFrame without ever changing the default clip region, nothing will be drawn.
  3659. When the picture frame is compared with the destination rectangle and the picture is scaled, the clip region is scaled too. In the process of scaling, the clip region you end up overflows and becomes empty, and your picture doesn’t get drawn. If you call ClipRect(thePort^.portRect) before you record the picture, the picture will be drawn correctly. The clipping on the destination port when playing back the picture is irrelevant: once a picture is incorrectly recorded, it is too late.
  3660. Further Reference:
  3661. •    QuickDraw
  3662. Plotting Small Icons
  3663. Imaging    M.IM.SmallIcons
  3664. Revised by:    James Beninghaus    October 1989
  3665. Written by:    James Beninghaus & Dennis Hescox    August 1989
  3666. This Technical Note discusses the 'SICN' resource format and how to plot one in a GrafPort.
  3667. Changes since August 1989:  Corrected errors in the Pascal code and spruced up the rest.
  3668. Introduction
  3669. Apple first introduced the 'SICN' resource so that the Script Manager could represent which country specific resources are installed in the system by displaying a small icon in the upper right corner of the menu bar.  You can pass a 'SICN' resource to the Notification Manager or Menu Manager, and they will draw it for you automatically—you should continue to let them do so.  However, if you want to draw a small icon in your application’s window, then this Note can help.
  3670. What does a 'SICN' look like?  Following is a 'SICN' representation of a dogcow to help answer this question:
  3671. SICN'            FatBits
  3672. There is reason to believe that this representation is actually a baby dogcow.  Due to the protective nature of parent dogcows, young dogcows are rarely seen.  This one was spotted during a DTS meeting after it drew attention to itself by crying “moo! woof!”.  (Note that this dogcow said “moo! woof!” because it was immature; adult dogcows naturally say, “Moof!”.)
  3673. 'SICN' Resource
  3674. A 'SICN' resource contains any number of small icon bit images.  Each small icon in a 'SICN' list describes a 16 by 16 pixel image and requires 32 bytes of storage.  Like an 'ICN#' resource, there is no count of the number of icons stored in a 'SICN'.  The following 'SICN' resource, in MPW Rez format, contains two small icons:
  3675.     resource 'SICN' (1984, "clarus") {
  3676.         {    /* array: 2 elements */
  3677.             $"00 48 00 B4 00 84 40 52 C0 41 A0 81 9F 8E 8F 18"
  3678.             $"40 18 40 18 47 88 48 48 48 48 44 44 3C 3C 00 00",
  3679.             $"00 48 00 FC 00 FC 40 7E C0 7F E0 FF FF FE FF F8"
  3680.             $"7F F8 7F F8 7F F8 78 78 78 78 7C 7C 3C 3C 00 00"
  3681.         }
  3682.     };
  3683. The Right Tools for the Job
  3684. The Macintosh Toolbox interfaces do not describe all the necessary data structures needed to work with 'SICN' resources.  As shown in the following example, defining the 'SICN' type as an array of 16 short integers and the handles and pointers to this array type make life much easier.
  3685. Pascal
  3686. TYPE
  3687.        SICN        = ARRAY[0 .. 15] of INTEGER;
  3688.        SICNList    = ARRAY[0 .. 0] of SICN;
  3689.        SICNPtr     = ^SICNList;
  3690.        SICNHand    = ^SICNPtr;
  3691. C
  3692. typedef    short       SICN[16];
  3693. typedef    SICN        *SICNList;
  3694. typedef    SICNList    *SICNHand;
  3695. The Missing Count
  3696. The 'SICN' resource does not provide a count to indicate the number of small icons contained within; however, you can easily determine this number by dividing the total size of the resource by the size of a single small icon.
  3697. Pascal
  3698. CONST
  3699.        mySICN      = 1984;
  3700. VAR
  3701.        theSICN     : SICNHand;
  3702.        theSize     : LONGINT;
  3703.        theCount    : LONGINT;
  3704.        theIndex    : LONGINT;
  3705. theSICN := SICNHand(GetResource('SICN', mySICN));
  3706. IF (theSICN <> NIL) THEN BEGIN
  3707.        theSize := GetHandleSize(Handle(theSICN));
  3708.        theCount := theSize DIV sizeof(SICN);
  3709. END;
  3710. C
  3711. #define mySICN         1984
  3712. SICNHand   theSICN;
  3713. long       theSize;
  3714. long       theCount;
  3715. long       theIndex;
  3716. theSICN = (SICNHand) GetResource('SICN', mySICN);
  3717. if (theSICN) {
  3718.        theSize = GetHandleSize((Handle)theSICN);
  3719.        theCount = theSize / sizeof(SICN);
  3720. }
  3721. The Plot 'SICN's
  3722. The example procedure PlotSICN draws one small icon of a 'SICN' resource.  It takes the handle from theSICN and the position in the list from theIndex within the rectangle theRect of the current GrafPort.
  3723. Following is an example call to PlotSICN which plots all the small icons in a resource into the same rectangle:
  3724. Pascal
  3725. SetRect(theRect, 0, 0, 16, 16);
  3726. FOR theIndex := 0 TO theCount-1 DO
  3727.        PlotSICN(theRect, theSICN, theIndex);
  3728. C
  3729. SetRect(&theRect, 0, 0, 16, 16);
  3730. for (theIndex = 0; theIndex < theCount ; ++theIndex)
  3731.        PlotSICN(&theRect, theSICN, theIndex);
  3732. Because PlotSICN uses _CopyBits and _CopyBits can move memory, you should lock the handle to the 'SICN' once the resource is loaded.  Notice that the PlotSICN procedure dereferences the 'SICN' handle, adds an offset, and copies the resulting value.  If the 'SICN' list moves in memory at this time, the bitmap’s baseAddr is useless.
  3733. To play it safe, PlotSICN saves a copy of the master pointer flags associated with the relocatable block, locks the block with a call to _HLock, and restores the flags after calling _CopyBits.  You should never examine, set, or clear these flags directly; you should always use the routines which are provided by the Memory Manager and Resource Manager.  Note that it is not necessary to check the value of the flag after getting it.
  3734. Pascal
  3735. PROCEDURE PlotSICN(theRect: Rect; theSICN: SICNHand; theIndex : INTEGER);
  3736. VAR
  3737.        state       : SignedByte;    { we want a chance to restore original state }
  3738.        srcBits     : BitMap;    { built up around 'SICN' data so we can _CopyBits }
  3739. BEGIN
  3740.        { check the index for a valid value }
  3741.        IF (GetHandleSize(Handle(theSICN)) DIV sizeof(SICN)) > theIndex THEN
  3742.        BEGIN
  3743.            { store the resource's current locked/unlocked condition }
  3744.            state := HGetState(Handle(theSICN));
  3745.            { lock the resource so it won't move during the _CopyBits call }
  3746.            HLock(Handle(theSICN));
  3747.            { set up the small icon's bitmap }
  3748.            {$PUSH}
  3749.            {$R-}            { turn off range checking }
  3750.            srcBits.baseAddr := Ptr(@theSICN^^[theIndex]);
  3751.            {$POP}
  3752.            srcBits.rowBytes := 2;
  3753.            SetRect(srcBits.bounds, 0, 0, 16, 16);
  3754.            { draw the small icon in the current grafport }
  3755.            CopyBits(srcBits,thePort^.portBits,srcBits.bounds,theRect,srcCopy,NIL);
  3756.            { restore the resource's locked/unlocked condition }
  3757.            HSetState(Handle(theSICN), state);
  3758.        END;
  3759. END;
  3760. C
  3761. void PlotSICN(Rect *theRect, SICNHand theSICN, long theIndex) {
  3762.        auto    char    state;    /* saves original flags of 'SICN' handle */
  3763.        auto    BitMap    srcBits;    /* built up around 'SICN' data so we can _CopyBits */
  3764.        /* check the index for a valid value */
  3765.        if ((GetHandleSize(Handle(theSICN)) / sizeof(SICN)) > theIndex) {
  3766.            /* store the resource's current locked/unlocked condition */
  3767.            state = HGetState((Handle)theSICN);
  3768.            /* lock the resource so it won't move during the _CopyBits call */
  3769.            HLock((Handle)theSICN);
  3770.            /* set up the small icon's bitmap */
  3771.            srcBits.baseAddr = (Ptr) (*theSICN)[theIndex];
  3772.            srcBits.rowBytes = 2;
  3773.            SetRect(&srcBits.bounds, 0, 0, 16, 16);
  3774.            /* draw the small icon in the current grafport */
  3775.            CopyBits(&srcBits,&(*qd.thePort).portBits,&srcBits.bounds,theRect,srcCopy,nil);
  3776.            /* restore the resource's locked/unlocked condition */
  3777.            HSetState((Handle) theSICN, state);
  3778.        }
  3779. }
  3780. That Was Easy
  3781. Now that you’ve seen it done, it looks pretty easy.  With minor modifications, some of the techniques in this Note could also be used to plot a bitmap of any dimension.
  3782. Further Reference:
  3783. •    Inside Macintosh, Volume I, QuickDraw
  3784. •    Inside Macintosh, Volume I, Toolbox Utilities
  3785. •    Inside Macintosh, Volume IV, The Memory Manager
  3786. •    Technical Note M.IM.OffscreenBitMap —
  3787.          Drawing Into an Off-Screen BitMap
  3788. •    Technical Note M.IM.DrawingIcons —
  3789.          Drawing Icons
  3790. Principia Off-Screen Graphics Environments
  3791. Imaging    M.IM.PrincipiaOffScreen
  3792. Updated by:    Forrest Tanaka    March 1992
  3793. Written by:    Forrest Tanaka    October 1991
  3794. Inspired by:    Jim Friedlander, Rick Blair, and Rich Collyer
  3795. Using Color QuickDraw to draw off screen is a common requirement of applications and other kinds of programs that run on the Macintosh. This Note discusses what Color QuickDraw needs in a graphics environment and how to create one for off-screen drawing. A brief discussion of GWorlds, which are off-screen graphics environments that are set up by the system, is given to help you decide whether to use them or the do-it-yourself techniques described in this Note for setting up an off-screen graphics environment. The author’s intent is to provide concepts and routines for creating an off-screen graphics environment, and also to explain why existing routines for off-screen drawing act as they do.
  3796. Many, many thanks go to Guillermo Ortiz, Konstantin Othmer, Bruce Leak, and Jon Zap for all their expertise on this subject, Rich Collyer, Rick Blair, and Jim Friedlander for paving the way, and especially to all people who inspired this update by asking great off-screen drawing questions.
  3797. Changes since October 1991:  A very embarrassing bug was found in CreateOffScreen and UpdateOffScreen. If you try to create a 16- or 32-bit off-screen graphics environment, you’ll just get a paramErr. It won’t do that now.
  3798. Off-Screening
  3799. The Macintosh, as with every other CPU ever made by Apple, has memory-mapped video. That is, what you see on the screen is just the visual representation of a part of memory that’s reserved for the video hardware (that’s stretching the truth just a bit in the case of the text screens of the original Apple computer, the Apple II line, and the Apple III because there’s also a character generator in those, but the overall process still looks roughly the same). If you change the contents of a memory location in this part of memory, then you’ll see the corresponding location on the screen change when the video hardware draws the next frame or field of video. The resident raster graphics package, QuickDraw in the case of the Macintosh, draws images by stuffing the right values into the right places in the part of memory reserved for the video display. The resulting image on the screen looks like a line or perhaps an oval if you asked QuickDraw to draw a line or an oval, or it could be an entire complex image if you asked QuickDraw to draw one. This is normal, on-screen drawing.
  3800. Because video memory is a part of RAM just like any other part of RAM in the memory map of the Macintosh (or almost like; video memory might exist on a NuBus™ video card, but it’s still RAM), QuickDraw can be told to draw into a part of memory that isn’t reserved for the video hardware, maybe into a part of your own application’s heap. When you tell QuickDraw to draw into a part of memory that’s not reserved for the video hardware, you can’t see any of the results. This is off-screen drawing. There are plenty of perfectly good reasons to do this, such as providing storage for a paint-style document or to smoothly animate an image, but the assumption here is that you have a perfectly good reason to do this so you’re more interested in the “how” of it instead of the “why” of it. If you need to know why, there are several books that cover off-screen drawing and the perfectly good reasons to do such a thing. A good place to start is Scott Knaster’s book, Macintosh Programming Secrets, referenced at the end of this Note.
  3801. This Note is divided into these major sections:
  3802. • The introduction is the part that you’re reading now.
  3803. • “The Building Blocks” provides an overview of the data structures that you need to tell Color QuickDraw to draw off screen.
  3804. • “Building the Blocks” discusses the construction and initialization of these data structures.
  3805. •    “Playing With Blocks” shows an example of the use of these structures to draw off screen.
  3806. •    “Put That Checkbook Away!” discusses some variations of these techniques to handle off-screen drawing for special cases.
  3807. •    “The GWorld Factor” provides a brief overview of GWorlds, how to use them, and how they compare and contrast to the manual techniques that are described in most of this Note.
  3808. Those of you who aren’t quite sure whether to use GWorlds or the do-it-yourself techniques might want to skip ahead for a moment to “The GWorld Factor” just in case doing it yourself is a waste of time. In any case, it’s a good idea to read this whole Note because the concepts are mostly the same whether you’re using GWorlds or not. GWorlds just make the process a lot easier, and they let you take advantage of the 8•24 GC video card. But, we’re not in that section of the Note yet.
  3809. The Building Blocks
  3810. Before you can tell QuickDraw to draw off of the screen, you’ll need to build three major data structures: a CGrafPort, a PixMap, and a GDevice. You’ll also need a couple of tables that define the colors involved with drawing to and copying from the off-screen image: the color table and the inverse table. Of course, you’ll need the pixel image itself, which is often called the “pixel buffer” or the “image buffer” or the “off-screen buffer” or just “the buffer.” It’s always called the “pixel image” in this Note. It doesn’t necessarily buffer anything anyway.
  3811. The CGrafPort
  3812. A CGrafPort describes a drawing environment, and it’s the color version of the GrafPort structure that’s described on pages 147 through 155 in the QuickDraw chapter of Inside Macintosh Volume I. The drawing environment consists of, among other things, the size and location of the graphics pen, the foreground and background colors to use when something is drawn, the pattern to use, the region to clip all drawing to, and the portion of a pixel image that the CGrafPort logically exists in. Any initialized CGrafPort or GrafPort can be set as the current port through the _SetPort routine. The current port is a set of parameters that are implicitly passed to most QuickDraw routines.
  3813. The most important reason to build a new CGrafPort when you draw off screen rather than using an existing CGrafPort is so that switching between drawing to an off-screen graphics environment and drawing to one or more windows (each of which is an extended GrafPort or CGrafPort structure) on the screen is very easy. Some people use just one CGrafPort to share between on-screen and off-screen graphics environments, and switch their PixMap structures to switch between drawing on screen and drawing off screen. That does work, but if the off-screen and on-screen graphics environments have a different clipRgn, visRgn, pen characteristic, portRect, or any other characteristics that are different, then those must be switched at that time too. If you instead create a CGrafPort that’s dedicated to one graphics environment, then a simple call to _SetPort effectively switches all these things for you at once. That’s why every window on the screen comes with its own port. A simple call to _SetPort switches between the characteristics of each window even if each window has radically different drawing characteristics.
  3814. The CGrafPort data structure is more completely described in the “Color QuickDraw” chapter of Inside Macintosh Volume V, pages 49 through 52, and in the “Graphics Overview” chapter of Inside Macintosh Volume VI, pages 16-12 through 16-13.
  3815. The PixMap
  3816. A pixel image alone is just a formless blob of memory. Pixel maps, defined by the PixMap structure, describe pixel images, giving them a form and structure that’s suitable for Color QuickDraw to draw into them and copy from them. The PixMap structure tells you the dimensions and location in memory of the pixel image, its coordinate system, and the depth and format of the pixels. Pixel maps that describe indexed-color pixel images additionally describe the colors that are represented by the values of the pixels in the pixel image. This is done through the color table, also known as the color look-up table or CLUT. Color tables are attached to pixel maps through their pmTable field. Direct-color pixel images have pixel values that describe their own colors, and so color tables aren’t needed for those.
  3817. The PixMap structure is described in the “Color QuickDraw” chapter of Inside Macintosh Volume V, pages 52 through 55, and in the “Graphics Overview” chapter of Inside Macintosh Volume VI, pages 16-11 through 16-12. The concept of direct-color and indexed-color pixels is described in this same chapter on pages 16-16 through 16-18, and also in the “Color QuickDraw” chapter of the same volume on pages 17-4 through 17-10.
  3818. The GDevice
  3819. Graphics devices, defined by the GDevice structure, describe color environments. They’re the most misunderstood data structure when it comes to off-screen graphics environments for three major reasons: first, they’re not originally documented as being relevant to humans; second, they look as though they’re only for screens; and third, it looks as though color tables describe color environments. We can dispose of these myths here: graphics devices are documented as being useful to humanity in this Note at least; they’re critically important for both on-screen and off-screen drawing; and color tables describe the colors in pixel images, not color environments.
  3820. What’s all this about color environments? In theory, there are virtually three hundred trillion colors available with Color QuickDraw through the 48-bit RGBColor record. In reality, there are never this many colors available, and in fact there might be only two. Color QuickDraw maps the theoretical color that you specify to the pixel value of the closest available color in the current color environment. This can be done with a color table, but that’s not very efficient. Finding the closest available color to an RGBColor in a color table means searching the entire color table for that one closest color. If that’s done just once, then performance isn’t much of an issue, but if it’s done many times, the performance hit could be significant. A very bad case of this is _CopyBits, where every pixel value in the source image is converted to an RGBColor by looking it up in the color table of the source PixMap. If the color table of the destination PixMap had to be searched to find the closest available color for every pixel in the source PixMap, then the performance of even the most straightforward _CopyBits call could be a lot slower than it has to be.
  3821. To avoid this performance hit, the current GDevice provides an inverse table and a device type which are used to determine the available set of colors. Inverse tables are anticolor tables. Where color tables give you a color for a given pixel value, inverse tables give you a pixel value for a given color. Every conceivable color table has a corresponding conceivable inverse table, just as every positive real number has a corresponding negative real number, or every Mr. Spock has a corresponding Mr. Spock with a goatee. The device type specifies whether the color environment uses the indexed-color, fixed-color, or direct-color model. In the direct-color model, the inverse table is empty. Only the indexed-color and direct-color models are described in this Note.
  3822. When you specify a color in an indexed-color environment, Color QuickDraw takes the RGBColor specification and converts it into a value that can be used as an index into the inverse table of the current GDevice. To do this conversion, Color QuickDraw takes the top few significant bits of each color component and combines them into part of a 16-bit word, blue bits in the least significant bits, green bits right above it, and the red bits right above green bits. Any unused bits are in the most significant bits of the 16-bit word. The resulting 16-bit word is used as an index into the inverse table. The value in the inverse table at that index is the pixel value which best represents that color in the current color environment. The number of bits of each component that are used is determined by what’s called the “resolution” of the inverse table. Almost always, the resolution of an inverse table is four bits, meaning the most significant four bits of each component are used to form the index into the inverse table. Figure 1 shows how an RGBColor record is converted to an index into an inverse table when the inverse-table resolution is four.
  3823. Figure 1  Conversion of RGBColor Record to Inverse-Table Index
  3824. The same process is used when _CopyBits is called with an indexed-color destination. Each pixel in the source pixel image is converted to an RGBColor either by doing a table look-up of the source pixel map’s color table if the source pixel image uses indexed colors, or by expanding the pixel value to an RGBColor record if the source pixel image uses direct colors. The resulting RGBColor is then used to look up a pixel value in the inverse table of the current GDevice, and this pixel value is put into the destination pixel image.
  3825. If you specify a color in a direct-color environment, then the resulting RGBColor is converted to a direct pixel value by the processes that are shown on pages 17-6 through 17-9 of the “Color QuickDraw” chapter of Inside Macintosh Volume VI.
  3826. Usually, inverse-table look-up involves an extra step to find what are called “hidden colors” using proprietary information that’s stored at the end of the inverse table. With an inverse-table resolution of four, only 16 shades of any particular component can be distinguished, and that’s often not enough. An inverse table with a resolution of five is much larger, but it still only gives you 32 shades of any component. Hidden colors are looked up after the normal inverse-table look-up to give a much more accurate representation of the specified color in the current color environment than the inverse-table look-up alone can produce. Sometimes, most notably when the arithmetic transfer modes are used or if dithering is used, the hidden colors are ignored.
  3827. When a new color table is assigned to a PixMap or when its existing color table is modified, then a new corresponding inverse table should be generated for the GDevice that’ll be used when drawing into that environment. Normally, this happens automatically without you having to do any more than inform Color QuickDraw of the change. This is described in more detail in  “Changing the Off-Screen Color Table”  later in this Note.
  3828. Graphics devices are documented in the “Graphics Devices” chapter of Inside Macintosh Volume VI which supersedes the “Graphics Devices” chapter of Inside Macintosh Volume V. They’re also discussed in the “Graphics Overview” chapter of Inside Macintosh Volume VI, pages 16-13 through 16-14. The inverse-table mechanism is described in the “Color Manager” chapter of Inside Macintosh Volume V, pages 137 through 139.
  3829. All Together Now
  3830. There are a lot of different ways to put the three structures together, and this Note discusses the architecture that’s shown in Figure 2. This architecture is  useful when you want a simple, atomic, off-screen graphics environment.
  3831. Figure 2  Relationships Between Structures for Off-Screen Drawing
  3832. Notice that there’s no way to get to the GDevice from the CGrafPort, nor is there a way to get to the CGrafPort from the GDevice, though the PixMap can be found through either one. Your application must keep track of both the CGrafPort and the GDevice.
  3833. Building the Blocks
  3834. As with just about any algorithm, there are many ways to put the different structures together that form an off-screen graphics environment. This section covers just one way to build the architecture that’s shown in Figure 2.
  3835. Building the CGrafPort
  3836. The CGrafPort structure is the easiest one to put together because the _OpenCPort routine initializes so many of the fields of the CGrafPort structure for you. It also allocates and initializes the structures that are attached to every CGrafPort, such as the visRgn, clipRgn, grafVars handle, and so forth. Most of these are initialized with values that are fine for general purposes, but the visRgn, clipRgn, and portRect fields should be set to the desired boundary rectangle of the off-screen graphics environment. What follows is an overview of each of the fields that you have to worry about when you’re setting up a CGrafPort for drawing off screen.
  3837. portPixMap    handle to the off-screen PixMap. _OpenCPort initializes this field to a copy of the PixMap that’s attached to the gdPMap field of the current GDevice. An overview of setting up this PixMap for drawing off screen is given in  “Building the PixMap” later in this Note.
  3838. portRect    specifies the rectangular area of the associated pixel image that this CGrafPort controls. This field should be set to the desired rectangular area of the off-screen image because _OpenCPort doesn’t necessarily initialize it to this size. Usually, the top-left corner of this rectangle has the coordinates (0, 0), but not necessarily so.
  3839. visRgn    handle to the region that specifies the visible area into which you can draw. _OpenCPort doesn’t necessarily initialize it to the size of the off-screen image, so it should be set to the same size and coordinates as the portRect and left at that. This field is more important for windows because parts of them can be hidden by other windows.
  3840. clipRgn    handle to the region that specifies the logical area into which you can draw. _OpenCPort initializes it to cover the entire QuickDraw coordinate plane. It’s usually a good idea to set it to the same size and coordinates as the portRect to avoid problems if the clipRgn is scaled or translated, which causes its signed integer coordinates to overflow and turn it into an empty region. One of the most common cases of this occurs when a picture that’s created in this CGrafPort is drawn into a destination rectangle that’s any larger than or translated from the original picture frame. Everything in the picture, including the clip region, is scaled to fit the destination rectangle. If the clip region covers the entire QuickDraw coordinate plane, then its coordinates overflow their signed integer bounds, and the clip region becomes logically empty. The result is that nothing is drawn.
  3841. The CreateOffScreen routine in Listing 1 creates an off-screen graphics environment, given a boundary rectangle, pixel depth, and color table, and it returns a new off-screen CGrafPort and GDevice, along with an error code. The desired pixel depth in bits per pixel is given in the depth parameter. If the pixel depth is eight or less, then an indexed-color graphics environment is created and a color table is required in the colors parameter. If the pixel depth is 16 or 32 bits per pixel and 32-Bit QuickDraw is available, then a direct-color graphics environment is created and the colors parameter is ignored. If 32-Bit QuickDraw isn’t available, then a pixel depth of 16 or 32 bits per pixel results in CreateOffScreen doing nothing more than returning a parameter error. A description of CreateOffScreen is given following the listing.
  3842. MPW Pascal Listing 1
  3843. FUNCTION CreateOffScreen(
  3844.    bounds:         Rect;       {Bounding rectangle of off-screen}
  3845.    depth:          Integer;    {Desired number of bits per pixel in off-screen}
  3846.    colors:         CTabHandle; {Color table to assign to off-screen}
  3847.    VAR retPort:    CGrafPtr;   {Returns a pointer to the new CGrafPort}
  3848.    VAR retGDevice: GDHandle    {Returns a handle to the new GDevice}
  3849.    ): OSErr;
  3850.    CONST
  3851.       kMaxRowBytes = $3FFE; {Maximum number of bytes in a row of pixels}
  3852.    VAR
  3853.       newPort:     CGrafPtr;     {Pointer to the new off-screen CGrafPort}
  3854.       newPixMap:   PixMapHandle; {Handle to the new off-screen PixMap}
  3855.       newDevice:   GDHandle;     {Handle to the new off-screen GDevice}
  3856.       qdVersion:   LongInt;      {Version of QuickDraw currently in use}
  3857.       savedPort:   GrafPtr;      {Pointer to GrafPort used for save/restore}
  3858.       savedState:  SignedByte;   {Saved state of color table handle}
  3859.       bytesPerRow: Integer;      {Number of bytes per row in the PixMap}
  3860.       error:       OSErr;        {Returns error code}
  3861. BEGIN
  3862.    (* Initialize a few things before we begin *)
  3863.    newPort := NIL;
  3864.    newPixMap := NIL;
  3865.    newDevice := NIL;
  3866.    error := noErr;
  3867.    (* Save the color table’s current state and make sure it isn’t purgeable *)
  3868.    IF colors <> NIL THEN
  3869.       BEGIN
  3870.          savedState := HGetState(Handle(colors));
  3871.          HNoPurge(Handle(colors));
  3872.       END;
  3873.    (* Calculate the number of bytes per row in the off-screen PixMap *)
  3874.    bytesPerRow := ((depth * (bounds.right - bounds.left) + 31) DIV 32) * 4;
  3875.    (* Get the current QuickDraw version *)
  3876.    error := Gestalt(gestaltQuickdrawVersion, qdVersion);
  3877.    error := noErr;
  3878.    (* Make sure depth is indexed or depth is direct and 32-Bit QD installed *)
  3879.    IF (depth = 1) OR (depth = 2) OR (depth = 4) OR (depth = 8) OR
  3880.          (((depth = 16) OR (depth = 32)) AND (qdVersion >= gestalt32BitQD)) THEN
  3881.       BEGIN
  3882.          (* Maximum number of bytes per row is 16,382; make sure within range *)
  3883.          IF bytesPerRow <= kMaxRowBytes THEN
  3884.             BEGIN
  3885.                (* Make sure a color table is provided if the depth is indexed *)
  3886.                IF depth <= 8 THEN
  3887.                   IF colors = NIL THEN
  3888.                      (* Indexed depth and clut is NIL; is parameter error *)
  3889.                      error := paramErr;
  3890.             END
  3891.          ELSE
  3892.             (* # of bytes per row is more than 16,382; is parameter error *)
  3893.             error := paramErr;
  3894.       END
  3895.    ELSE
  3896.       (* Pixel depth isn’t valid; is parameter error *)
  3897.       error := paramErr;
  3898.    (* If sanity checks succeed, then allocate a new CGrafPort *)
  3899.    IF error = noErr THEN
  3900.       BEGIN
  3901.          newPort := CGrafPtr(NewPtr(SizeOf (CGrafPort)));
  3902.          IF newPort <> NIL THEN
  3903.             BEGIN
  3904.                (* Save the current port *)
  3905.                GetPort(savedPort);
  3906.                (* Initialize the new CGrafPort and make it the current port *)
  3907.                OpenCPort(newPort);
  3908.                (* Set portRect, visRgn, and clipRgn to the given bounds rect *)
  3909.                newPort^.portRect := bounds;
  3910.                RectRgn(newPort^.visRgn, bounds);
  3911.                ClipRect(bounds);
  3912.                (* Initialize the new PixMap for off-screen drawing *)
  3913.                error := SetUpPixMap(depth, bounds, colors, bytesPerRow,
  3914.                      newPort^.portPixMap);
  3915.                IF error = noErr THEN
  3916.                   BEGIN
  3917.                      (* Grab the initialized PixMap handle *)
  3918.                      newPixMap := newPort^.portPixMap;
  3919.                      (* Allocate and initialize a new GDevice *)
  3920.                      error := CreateGDevice(newPixMap, newDevice);
  3921.                   END;
  3922.                (* Restore the saved port *)
  3923.                SetPort(savedPort);
  3924.             END
  3925.          ELSE
  3926.             error := MemError;
  3927.       END;
  3928.    (* Restore the given state of the color table *)
  3929.    IF colors <> NIL THEN
  3930.       HSetState(Handle(colors), savedState);
  3931.    (* One Last Look Around The House Before We Go… *)
  3932.    IF error <> noErr THEN
  3933.       BEGIN
  3934.          (* Some error occurred; dispose of everything we allocated *)
  3935.          IF newPixMap <> NIL THEN
  3936.             BEGIN
  3937.                DisposCTable(newPixMap^^.pmTable);
  3938.                DisposPtr(newPixMap^^.baseAddr);
  3939.             END;
  3940.          IF newDevice <> NIL THEN
  3941.             BEGIN
  3942.                DisposHandle(Handle(newDevice^^.gdITable));
  3943.                DisposHandle(Handle(newDevice));
  3944.             END;
  3945.          IF newPort <> NIL THEN
  3946.             BEGIN
  3947.                CloseCPort(newPort);
  3948.                DisposPtr(Ptr(newPort));
  3949.             END;
  3950.       END
  3951.    ELSE
  3952.       BEGIN
  3953.          (* Everything’s OK; return refs to off-screen CGrafPort and GDevice *)
  3954.          retPort := newPort;
  3955.          retGDevice := newDevice;
  3956.       END;
  3957.    CreateOffScreen := error;
  3958. END;
  3959. MPW C Listing 1
  3960. #define kMaxRowBytes 0x3FFE /* Maximum number of bytes in a row of pixels */
  3961. OSErr CreateOffScreen(
  3962.     Rect       *bounds,     /* Bounding rectangle of off-screen */
  3963.     short      depth,       /* Desired number of bits per pixel in off-screen */
  3964.     CTabHandle colors,      /* Color table to assign to off-screen */
  3965.     CGrafPtr   *retPort,    /* Returns a pointer to the new CGrafPort */
  3966.     GDHandle   *retGDevice) /* Returns a handle to the new GDevice */
  3967. {
  3968.     CGrafPtr     newPort;     /* Pointer to the new off-screen CGrafPort */
  3969.     PixMapHandle newPixMap;   /* Handle to the new off-screen PixMap */
  3970.     GDHandle     newDevice;   /* Handle to the new off-screen GDevice */
  3971.     long         qdVersion;   /* Version of QuickDraw currently in use */
  3972.     GrafPtr      savedPort;   /* Pointer to GrafPort used for save/restore */
  3973.     SignedByte   savedState;  /* Saved state of color table handle */
  3974.     short        bytesPerRow; /* Number of bytes per row in the PixMap */
  3975.     OSErr        error;       /* Returns error code */
  3976.     /* Initialize a few things before we begin */
  3977.     newPort = nil;
  3978.     newPixMap = nil;
  3979.     newDevice = nil;
  3980.     error = noErr;
  3981.     /* Save the color table’s current state and make sure it isn’t purgeable */
  3982.     if (colors != nil)
  3983.     {
  3984.         savedState = HGetState( (Handle)colors );
  3985.         HNoPurge( (Handle)colors );
  3986.     }
  3987.     /* Calculate the number of bytes per row in the off-screen PixMap */
  3988.     bytesPerRow = ((depth * (bounds->right - bounds->left) + 31) >> 5) << 2;
  3989.     /* Get the current QuickDraw version */
  3990.     (void)Gestalt( gestaltQuickdrawVersion, &qdVersion );
  3991.     /* Make sure depth is indexed or depth is direct and 32-Bit QD installed */
  3992.     if (depth == 1 || depth == 2 || depth == 4 || depth == 8 ||
  3993.             ((depth == 16 || depth == 32) && qdVersion >= gestalt32BitQD))
  3994.     {
  3995.         /* Maximum number of bytes per row is 16,382; make sure within range */
  3996.         if (bytesPerRow <= kMaxRowBytes)
  3997.         {
  3998.             /* Make sure a color table is provided if the depth is indexed */
  3999.             if (depth <= 8)
  4000.                 if (colors == nil)
  4001.                   /* Indexed depth and clut is NIL; is parameter error */
  4002.                   error = paramErr;
  4003.         }
  4004.         else
  4005.             /* # of bytes per row is more than 16,382; is parameter error */
  4006.             error = paramErr;
  4007.     }
  4008.     else
  4009.         /* Pixel depth isn’t valid; is parameter error */
  4010.         error = paramErr;
  4011.     /* If sanity checks succeed, then allocate a new CGrafPort */
  4012.     if (error == noErr)
  4013.     {
  4014.         newPort = (CGrafPtr)NewPtr( sizeof (CGrafPort) );
  4015.         if (newPort != nil)
  4016.         {
  4017.             /* Save the current port */
  4018.             GetPort( &savedPort );
  4019.             /* Initialize the new CGrafPort and make it the current port */
  4020.             OpenCPort( newPort );
  4021.             /* Set portRect, visRgn, and clipRgn to the given bounds rect */
  4022.             newPort->portRect = *bounds;
  4023.             RectRgn( newPort->visRgn, bounds );
  4024.             ClipRect( bounds );
  4025.             /* Initialize the new PixMap for off-screen drawing */
  4026.             error = SetUpPixMap( depth, bounds, colors, bytesPerRow,
  4027.                     newPort->portPixMap );
  4028.             if (error == noErr)
  4029.             {
  4030.                 /* Grab the initialized PixMap handle */
  4031.                 newPixMap = newPort->portPixMap;
  4032.                 /* Allocate and initialize a new GDevice */
  4033.                 error = CreateGDevice( newPixMap, &newDevice );
  4034.             }
  4035.             /* Restore the saved port */
  4036.             SetPort( savedPort );
  4037.         }
  4038.         else
  4039.             error = MemError();
  4040.     }
  4041.     /* Restore the given state of the color table */
  4042.     if (colors != nil)
  4043.         HSetState( (Handle)colors, savedState );
  4044.     /* One Last Look Around The House Before We Go… */
  4045.     if (error != noErr)
  4046.     {
  4047.         /* Some error occurred; dispose of everything we allocated */
  4048.         if (newPixMap != nil)
  4049.         {
  4050.             DisposCTable( (**newPixMap).pmTable );
  4051.             DisposPtr( (**newPixMap).baseAddr );
  4052.         }
  4053.         if (newDevice != nil)
  4054.         {
  4055.             DisposHandle( (Handle)(**newDevice).gdITable );
  4056.             DisposHandle( (Handle)newDevice );
  4057.         }
  4058.         if (newPort != nil)
  4059.         {
  4060.             CloseCPort( newPort );
  4061.             DisposPtr( (Ptr)newPort );
  4062.         }
  4063.     }
  4064.     else
  4065.     {
  4066.         /* Everything’s OK; return refs to off-screen CGrafPort and GDevice */
  4067.         *retPort = newPort;
  4068.         *retGDevice = newDevice;
  4069.     }
  4070.     return error;
  4071. }
  4072. CreateOffScreen begins by making sure that the color table, if there is one, doesn’t get purged during the time that the off-screen graphics environment is created. Then, a sanity check is done for the given depth, bounds, and color table. The depth must be either 1, 2, 4, or 8 bits per pixel, or additionally 16 or 32 bits per pixel if 32-Bit QuickDraw is available. If these conditions aren’t satisfied, then it’s decided that there’s an error in the parameter list, and CreateOffScreen does nothing more. To determine whether 32-Bit QuickDraw is available or not, the _Gestalt routine is used. If _Gestalt returns a value that’s equal to or greater than the constant gestalt32BitQD, then 32-Bit QuickDraw is available and depths of 16 and 32 bits per pixel are supported. It’s not necessary to determine whether _Gestalt is available or not because it’s implemented as glue code in the Macintosh Programmer’s Workshop.
  4073. A check is then done to determine whether the number of bytes in each row of the off-screen pixel image is too much for QuickDraw to handle. Color QuickDraw can handle up to and including 16,382 ($3FFE) bytes in each row of any pixel image. If the required number of bytes per row exceeds this amount, then CreateOffScreen decides that there’s an error in the parameter list and does nothing more. The minimum number of bytes in a row that’s enough to cover the given boundary rectangle at the given pixel depth is calculated with the formula:
  4074.   bytesPerRow := ((depth * (bounds.right - bounds.left) + 31) DIV 32) * 4;
  4075. This formula multiplies the number of pixels across the PixMap by the pixel depth to get the number of bits, and then this is divided by eight to get the number of bytes. This division by eight looks very strange because the number of bytes per row must be even, so this formula takes advantage of integer division and multiplication to make the result come out even. This particular formula additionally makes sure that the number of bytes per row is a multiple of four. This helps optimize the performance of Color QuickDraw operations because it allows Color QuickDraw to refer to each row beginning on a long word boundary in memory.
  4076. The last sanity check is to make sure that a color table is given as a parameter if it’s needed. Indexed-color graphics environments need color tables, so if the given pixel depth is eight or less (which implies an indexed-color graphics environment) and the given color table is NIL, then CreateOffScreen decides that there’s an error in the parameter list and does nothing more. If the given pixel depth is 16 or 32 (which implies a direct-color graphics environment), then CreateOffScreen ignores the given color table.
  4077. If all the sanity checks succeed, then the off-screen CGrafPort is allocated using a call to _NewPtr, and then it’s initialized and opened as a CGrafPort by passing the resulting pointer to _OpenCPort. Because _OpenCPort makes the new CGrafPort the current port, the current port is first saved so that it can be restored as the current port when CreateOffScreen is done.
  4078. As mentioned above, the _OpenCPort doesn’t necessarily initialize the portRect, visRgn, and clipRgn of the new CGrafPort to the areas that are needed for any particular off-screen graphics environment. So, the given boundary rectangle is assigned to the portRect field, _RectRgn is called to make the visRgn equal to the given boundary rectangle, and _ClipRect is called to set the clipRgn so that it’s equal to the given boundary rectangle.
  4079. The PixMap in the portPixMap field needs to be initialized for off-screen drawing, and that’s handled by the SetUpPixMap routine that’s described and defined in “Building the PixMap” later in this Note. Similarly, the off-screen GDevice must be created and initialized. That’s handled by the CreateGDevice routine that’s described and defined in “Building the GDevice” later in this Note.
  4080. Once these things are done, CreateOffScreen returns a pointer to the off-screen CGrafPort in the retPort parameter and a handle to the off-screen GDevice in the retGDevice parameter. The way to use these references is described in “Playing With Blocks”  later in this Note.
  4081. Building the PixMap
  4082. _OpenCPort initializes the portPixMap field of the CGrafPort it’s initializing with a copy of the PixMap of the current GDevice. When the CreateOffScreen routine described earlier executes, the current GDevice is unknown. So, all the fields of the PixMap that the new CGrafPort receives must be initialized so that it can be used for drawing off screen.* What follows is an overview of each of the PixMap fields and how they should be initialized for off-screen drawing.
  4083. baseAddr    pointer to the off-screen pixel image. The off-screen pixel image is allocated as a nonrelocatable block in the heap. The size of this block of memory is calculated from the rowBytes field, described next, multiplied by the number of rows in the given boundary rectangle.
  4084. rowBytes    number of bytes in each row of the pixel image. This value is calculated from the formula that’s given in the CreateOffScreen routine. The most significant bit of this field should be set so that Color QuickDraw knows that this is a PixMap rather than a BitMap. The maximum value, ignoring the most significant bit, is 16,382.
  4085. bounds    defines the coordinate system and the dimensions of the pixel image. For most off-screen drawing, this should be a rectangle that covers the entire off-screen graphics environment.
  4086. pmVersion    set of internally and externally defined flags. As of 32-Bit QuickDraw 1.2, only the baseAddr32 flag is defined externally. This flag is described in “Choosing Your Off-Screen Memory” later in this Note. For most off-screen drawing, this field is set to zero.
  4087. packType    image compression scheme for pictures. The options for this field are discussed in the “Graphics Overview” chapter of Inside Macintosh Volume VI, pages 17-22 through 17-23. In this Note, image compression isn’t discussed so this field is set to zero.
  4088. packSize    internally used field. This field is always set to zero.
  4089. hRes    horizontal resolution of the pixel map. By default, the QuickDraw resolution is 72 dots per inch,which is the value this Note uses. This is a fixed-point field, so the actual value in this field is $00480000.
  4090. vRes    vertical resolution of the pixel map. See the hRes description.
  4091. pixelType    format of the pixels. In indexed-color pixel maps, this field holds zero. In direct-color pixel maps, this field holds the RGBDirect constant, which is equal to 16.
  4092. pixelSize    number of bits in every pixel. For indexed-color pixels, this is 1, 2, 4, or 8 bits per pixel. For direct-color pixels, this is 16 or 32 bits per pixel.
  4093. cmpCount    number of components in every pixel. In indexed-color pixel maps, this field is set to 1. In direct-color pixel maps, this field is set to 3. Sometimes it’s handy to set this field to 4 in 32-bit deep pixel maps when they’re being saved in a picture. See the “Color QuickDraw” chapter of Inside Macintosh Volume VI, page 17-23, for details about this.
  4094. cmpSize    number of bits in each color component. In indexed-color pixel maps, this field is set to the same value that’s in the pixelSize field. In 16-bit deep direct pixel maps, this field is set to 5. In 32-bit deep direct pixel maps, this field is set to 8.
  4095. planeBytes    not currently defined. This field is set to zero.
  4096. pmTable    handle to the color table for indexed-color pixel maps. A method to create a color table is given in “About That Creation Thing . . .” later in this Note. In direct-color pixel maps, this field contains a handle to a dummy color table, and building one of these is shown in the SetUpPixMap routine in Listing 2.
  4097. pmReserved    not currently defined. This field is set to zero.
  4098. The SetUpPixMap routine in Listing 2 initializes the PixMap that’s passed to it in the aPixMap parameter so that it can be used in an off-screen graphics environment. The depth, bounds, and color parameters are the same as the ones passed to the CreateOffScreen routine. The bytesPerRow parameter is the number of bytes in each row of the off-screen pixel image. A description of SetUpPixMap follows the listing.
  4099. MPW Pascal Listing 2
  4100. FUNCTION SetUpPixMap(
  4101.    depth:       Integer;     {Desired number of bits/pixel in off-screen}
  4102.    bound:       Rect;        {Bounding rectangle of off-screen}
  4103.    colors:      CTabHandle;  {Color table to assign to off-screen}
  4104.    bytesPerRow: Integer;     {Number of bytes in each row of pixels}
  4105.    aPixMap:     PixMapHandle {Handle to the PixMap being initialized}
  4106.    ): OSErr;
  4107.    CONST
  4108.       kDefaultRes = $00480000; {Default resolution is 72 DPI; Fixed type}
  4109.    VAR
  4110.       newColors:   CTabHandle; {Color table used for the off-screen PixMap}
  4111.       offBaseAddr: Ptr;        {Pointer to the off-screen pixel image}
  4112.       error:       OSErr;      {Returns error code}
  4113. BEGIN
  4114.    error := noErr;
  4115.    newColors := NIL;
  4116.     offBaseAddr := NIL;
  4117.    (* Clone the clut if indexed color; allocate a dummy clut if direct color *)
  4118.    IF depth <= 8 THEN
  4119.       BEGIN
  4120.          newColors := colors;
  4121.          error := HandToHand(Handle(newColors));
  4122.       END
  4123.    ELSE
  4124.       BEGIN
  4125.          newColors := CTabHandle(NewHandle(SizeOf(ColorTable) -
  4126.                SizeOf(CSpecArray)));
  4127.          error := MemError;
  4128.       END;
  4129.    IF error = noErr THEN
  4130.       BEGIN
  4131.          (* Allocate pixel image; long integer multiplication avoids overflow *)
  4132.          offBaseAddr := NewPtr(LongInt(bytesPerRow) * (bound.bottom -
  4133.                bound.top));
  4134.          IF offBaseAddr <> NIL THEN
  4135.             WITH aPixMap^^ DO
  4136.                BEGIN
  4137.                   (* Initialize fields common to indexed and direct PixMaps *)
  4138.                   baseAddr := offBaseAddr;     {Point to image}
  4139.                   rowBytes := BOR(bytesPerRow, {MSB set for PixMap}
  4140.                         $8000);
  4141.                   bounds := bound;             {Use given bounds}
  4142.                   pmVersion := 0;              {No special stuff}
  4143.                   packType := 0;               {Default PICT pack}
  4144.                   packSize := 0;               {Always zero when in memory}
  4145.                   hRes := kDefaultRes;         {72 DPI default resolution}
  4146.                   vRes := kDefaultRes;         {72 DPI default resolution}
  4147.                   pixelSize := depth;          {Set number of bits/pixel}
  4148.                   planeBytes := 0;             {Not used}
  4149.                   pmReserved := 0;             {Not used}
  4150.                   (* Initialize fields specific to indexed and direct PixMaps *)
  4151.                   IF depth <= 8 THEN
  4152.                      BEGIN
  4153.                         (* PixMap is indexed *)
  4154.                         pixelType := 0;       {Indicates indexed}
  4155.                         cmpCount := 1;        {Have 1 component}
  4156.                         cmpSize := depth;     {Component size=depth}
  4157.                         pmTable := newColors; {Handle to CLUT}
  4158.                      END
  4159.                   ELSE
  4160.                      BEGIN
  4161.                         (* PixMap is direct *)
  4162.                         pixelType := RGBDirect; {Indicates direct}
  4163.                         cmpCount := 3;          {Have 3 components}
  4164.                         IF depth = 16 THEN
  4165.                            cmpSize := 5         {5 bits/component}
  4166.                         ELSE
  4167.                            cmpSize := 8;        {8 bits/component}
  4168.                         (* Initialize fields of the dummy color table *)
  4169.                         newColors^^.ctSeed := 3 * aPixMap^^.cmpSize;
  4170.                         newColors^^.ctFlags := 0;
  4171.                         newColors^^.ctSize := 0;
  4172.                         pmTable := newColors;
  4173.                      END;
  4174.                END
  4175.          ELSE
  4176.             error := MemError;
  4177.       END
  4178.    ELSE
  4179.       newColors := NIL;
  4180.    (* If no errors occurred, return a handle to the new off-screen PixMap *)
  4181.    IF error <> noErr THEN
  4182.       BEGIN
  4183.          IF newColors <> NIL THEN
  4184.             DisposCTable(newColors);
  4185.       END;
  4186.     (* Return the error code *)
  4187.     SetUpPixMap := error;
  4188. END;
  4189. MPW C Listing 2
  4190. #define kDefaultRes 0x00480000 /* Default resolution is 72 DPI; Fixed type */
  4191. OSErr SetUpPixMap(
  4192.     short        depth,       /* Desired number of bits/pixel in off-screen */
  4193.     Rect         *bounds,     /* Bounding rectangle of off-screen */
  4194.     CTabHandle   colors,      /* Color table to assign to off-screen */
  4195.     short        bytesPerRow, /* Number of bytes per row in the PixMap */
  4196.     PixMapHandle aPixMap)     /* Handle to the PixMap being initialized */
  4197. {
  4198.     CTabHandle newColors;   /* Color table used for the off-screen PixMap */
  4199.     Ptr        offBaseAddr; /* Pointer to the off-screen pixel image */
  4200.     OSErr      error;       /* Returns error code */
  4201.     error = noErr;
  4202.     newColors = nil;
  4203.     offBaseAddr = nil;
  4204.     /* Clone the clut if indexed color; allocate a dummy clut if direct color */
  4205.     if (depth <= 8)
  4206.     {
  4207.         newColors = colors;
  4208.         error = HandToHand( (Handle *)&newColors );
  4209.     }
  4210.     else
  4211.     {
  4212.         newColors = (CTabHandle)NewHandle( sizeof (ColorTable) -
  4213.                 sizeof (CSpecArray) );
  4214.         error = MemError();
  4215.     }
  4216.     if (error == noErr)
  4217.     {
  4218.         /* Allocate pixel image; long integer multiplication avoids overflow */
  4219.         offBaseAddr = NewPtr( (unsigned long)bytesPerRow * (bounds->bottom -
  4220.                 bounds->top) );
  4221.         if (offBaseAddr != nil)
  4222.         {
  4223.             /* Initialize fields common to indexed and direct PixMaps */
  4224.             (**aPixMap).baseAddr = offBaseAddr;  /* Point to image */
  4225.             (**aPixMap).rowBytes = bytesPerRow | /* MSB set for PixMap */
  4226.                     0x8000;
  4227.             (**aPixMap).bounds = *bounds;        /* Use given bounds */
  4228.             (**aPixMap).pmVersion = 0;           /* No special stuff */
  4229.             (**aPixMap).packType = 0;            /* Default PICT pack */
  4230.             (**aPixMap).packSize = 0;            /* Always zero in mem */
  4231.             (**aPixMap).hRes = kDefaultRes;      /* 72 DPI default res */
  4232.             (**aPixMap).vRes = kDefaultRes;      /* 72 DPI default res */
  4233.             (**aPixMap).pixelSize = depth;       /* Set # bits/pixel */
  4234.             (**aPixMap).planeBytes = 0;          /* Not used */
  4235.             (**aPixMap).pmReserved = 0;          /* Not used */
  4236.             /* Initialize fields specific to indexed and direct PixMaps */
  4237.             if (depth <= 8)
  4238.             {
  4239.                 /* PixMap is indexed */
  4240.                 (**aPixMap).pixelType = 0;       /* Indicates indexed */
  4241.                 (**aPixMap).cmpCount = 1;        /* Have 1 component */
  4242.                 (**aPixMap).cmpSize = depth;     /* Component size=depth */
  4243.                 (**aPixMap).pmTable = newColors; /* Handle to CLUT */
  4244.             }
  4245.             else
  4246.             {
  4247.                 /* PixMap is direct */
  4248.                 (**aPixMap).pixelType = RGBDirect; /* Indicates direct */
  4249.                 (**aPixMap).cmpCount = 3;          /* Have 3 components */
  4250.                 if (depth == 16)
  4251.                     (**aPixMap).cmpSize = 5;       /* 5 bits/component */
  4252.                 else
  4253.                     (**aPixMap).cmpSize = 8;       /* 8 bits/component */
  4254.                 (**newColors).ctSeed = 3 * (**aPixMap).cmpSize;
  4255.                 (**newColors).ctFlags = 0;
  4256.                 (**newColors).ctSize = 0;
  4257.                 (**aPixMap).pmTable = newColors;
  4258.             }
  4259.         }
  4260.         else
  4261.             error = MemError();
  4262.     }
  4263.     else
  4264.         newColors = nil;
  4265.     /* If no errors occurred, return a handle to the new off-screen PixMap */
  4266.     if (error != noErr)
  4267.     {
  4268.         if (newColors != nil)
  4269.             DisposCTable( newColors );
  4270.     }
  4271.     /* Return the error code */
  4272.     return error;
  4273. }
  4274. SetUpPixMap begins by copying the given color table if an indexed-color graphics environment is being built, or allocating a dummy color table if a direct-color graphics environment is being built. A copy of the color table is made because this allows the given color table and the off-screen graphics environment’s color table to be manipulated independently without interfering with each other, and this lets the off-screen graphics environment routines manipulate the color table without needing to worry about whether the color table is a 'clut' resource or not. The dummy color table is made so that routines which assume that every PixMap has a color table won’t do something catastrophic if they find a NIL color table. The off-screen pixel image is then allocated as a nonrelocatable block in the application’s heap.
  4275. Some of the fields of a PixMap have to be initialized differently depending upon whether the indexed-color model or the direct-color model is being used. So, the fields that are the same regardless of the color model that’s being used are assigned first. Then the desired pixel depth is compared to 8. If the depth is less than or equal to 8, then the rest of the fields are initialized for the indexed-color model. Otherwise, the rest of the fields are initialized for the direct color model. In the case of the direct-color model, the dummy color table is initialized to have no CSpecArray entries and its ctSeed field is set to three times the component size. This dummy color table is then installed into the PixMap.
  4276. Once SetUpPixMap completes, the PixMap of the new CGrafPort is ready to hold an off-screen image. It’s not quite ready to be drawn into with Color QuickDraw though. To do that, the off-screen GDevice is still needed; the construction and initialization of the GDevice are covered in the next section.
  4277. Building the GDevice
  4278. The _OpenCPort routine automatically allocates and initializes a PixMap, and the SetUpPixMap routine reinitializes that existing PixMap. _OpenCPort doesn’t allocate nor initialize a GDevice, so one has to be created from scratch. Pages 21-20 through 21-21 of “The Graphics Devices Manager” chapter of Inside Macintosh Volume VI describe the _NewGDevice routine. This routine seems as though it’s the ticket to getting a GDevice for off-screen drawing, but it always allocates the new GDevice in the system heap. That’s not so good because if your program unexpectedly quits or if you just forget to dispose of the GDevice before you quit for real, the GDevice gets orphaned in the system heap. To prevent this from happening, _NewGDevice should be ignored and the off-screen GDevice should instead be allocated and initialized from scratch. What follows is a description of how each field of the GDevice structure should be initialized.
  4279. gdRefNum    reference number of video driver. Off-screen graphics environments don’t need to have video drivers because there’s no video device associated with them, so this field is set to zero.
  4280. gdID    used to identify specific GDevice structures from color-search procedures. This isn’t necessary for off-screen drawing, so this is normally set to zero.
  4281. gdType    type of GDevice. This field is set to the constant clutType (equal to zero) for an indexed-color environment and set to the constant directType (equal to 2) for a direct-color environment.
  4282. gdITable    handle to the inverse table. Initially, this field is set to an arbitrarily small handle. Later, the _MakeITable routine is used to resize and initialize this handle to a real inverse table.
  4283. gdResPref    inverse-table resolution. When _MakeITable is called by QuickDraw, the value of this field is used as the inverse-table resolution. Almost all inverse tables have a resolution of 4. There are some cases when a inverse-table resolution of 5 is useful, particularly when the arithmetic transfer modes are used with _CopyBits. See “The GDevice” earlier in this Note.
  4284. gdSearchProc    pointer to the color-search procedure. If a color-search procedure is needed, this field can be set later by calling the _AddSearch routine (see the “Color Manager” chapter of Inside Macintosh Volume V, pages 145 through 147). Usually, this field is just set to NIL and left at that.
  4285. gdCompProc    pointer to the color-complement procedure. If a color-complement procedure is needed, this field can be set later by calling the _AddComp routine (see the “Color Manager” chapter of Inside Macintosh Volume V, pages 145 through 147). Usually, this field is set to NIL and left at that.
  4286. gdFlags    flags indicating certain states of the GDevice. This field should initially be set to zeroes. After the GDevice has been built, these flags can be set with the _SetDeviceAttrs routine (see the “Graphics Devices Manager” chapter of Inside Macintosh Volume VI, pages 21-10 and 21-22).
  4287. gdPMap    handle to a PixMap. A handle to the PixMap of the CGrafPort that was created earlier is put into this field.
  4288. gdRefCon    miscellaneous data. _CalcCMask and _SeedCFill use this field as described on pages 71 through 72 of Inside Macintosh Volume V. Initially, this field is set to zero.
  4289. gdNextGD    handle to next GDevice in the GDevice list. The system maintains a linked list of GDevice records in which there’s one GDevice for every screen, and the links are kept in this field. Off-screen GDevice structures should never be put into this list, so this field should be set to NIL.
  4290. gdRect    rectangle of GDevice. Strictly speaking, this field is used only for screens, but it should be the same as the bounds rectangle of the off-screen PixMap.
  4291. gdMode    current video mode. This field is used by video drivers to keep track of the current mode that the video device is in. For off-screen GDevice structures, this field should be set to -1.
  4292. gdCC…    These four fields are used only with GDevice structures for screens. For off-screen GDevice structures, these fields should be set to zero.
  4293. gdReserved    not currently defined. This field is set to zero.
  4294. The CreateGDevice routine shown below in Listing 3 allocates and initializes a GDevice structure. It takes the initialized off-screen PixMap in the basePixMap parameter and returns the initialized GDevice in the retGDevice parameter. If any error occurs, any memory that’s allocated is disposed of and the result code is returned as a function result.
  4295. MPW Pascal Listing 3
  4296. FUNCTION CreateGDevice(
  4297.    basePixMap:     PixMapHandle; {Handle to the PixMap to base GDevice on}
  4298.    VAR retGDevice: GDHandle      {Returns a handle to the new GDevice}
  4299.    ): OSErr;
  4300.    CONST
  4301.       kITabRes = 4; {Inverse-table resolution}
  4302.    VAR
  4303.       newDevice:  GDHandle;   {Handle to the new GDevice}
  4304.       embryoITab: ITabHandle; {Handle to the embryonic inverse table}
  4305.       error:      OSErr;      {Error code}
  4306. BEGIN
  4307.    (* Initialize a few things before we begin *)
  4308.    error := noErr;
  4309.    newDevice := NIL;
  4310.    embryoITab := NIL;
  4311.    (* Allocate memory for the new GDevice *)
  4312.    newDevice := GDHandle(NewHandle(SizeOf(GDevice)));
  4313.    IF newDevice <> NIL THEN
  4314.       BEGIN
  4315.          (* Allocate the embryonic inverse table *)
  4316.          embryoITab := ITabHandle(NewHandleClear(2));
  4317.          IF embryoITab <> NIL THEN
  4318.             BEGIN
  4319.                (* Initialize the new GDevice fields *)
  4320.                WITH newDevice^^ DO
  4321.                   BEGIN
  4322.                      gdRefNum := 0;                 {Only used for screens}
  4323.                      gdID := 0;                     {Won’t normally use}
  4324.                      IF basePixMap^^.pixelSize <= 8 THEN
  4325.                         gdType := clutType          {Depth≤8; clut device}
  4326.                      ELSE
  4327.                         gdType := directType;       {Depth>8; direct device}
  4328.                      gdITable := embryoITab;        {2-byte handle for now}
  4329.                      gdResPref := kITabRes;         {Normal inv table res}
  4330.                      gdSearchProc := NIL;           {No color-search proc}
  4331.                      gdCompProc := NIL;             {No complement proc}
  4332.                      gdFlags := 0;                  {Will set these later}
  4333.                      gdPMap := basePixMap;          {Reference our PixMap}
  4334.                      gdRefCon := 0;                 {Won’t normally use}
  4335.                      gdNextGD := NIL;               {Not in GDevice list}
  4336.                      gdRect := basePixMap^^.bounds; {Use PixMap dimensions}
  4337.                      gdMode := -1;                  {For nonscreens}
  4338.                      gdCCBytes := 0;                {Only used for screens}
  4339.                      gdCCDepth := 0;                {Only used for screens}
  4340.                      gdCCXData := NIL;              {Only used for screens}
  4341.                      gdCCXMask := NIL;              {Only used for screens}
  4342.                      gdReserved := 0;               {Currently unused}
  4343.                   END;
  4344.                (* Set color-device bit if PixMap isn’t black & white *)
  4345.                IF basePixMap^^.pixelSize > 1 THEN
  4346.                   SetDeviceAttribute(newDevice, gdDevType, true);
  4347.                (* Set bit to indicate that the GDevice has no video driver *)
  4348.                SetDeviceAttribute(newDevice, noDriver, true);
  4349.                (* Initialize the inverse table *)
  4350.                IF basePixMap^^.pixelSize <= 8 THEN
  4351.                   BEGIN
  4352.                      MakeITable(basePixMap^^.pmTable, newDevice^^.gdITable,
  4353.                            newDevice^^.gdResPref);
  4354.                      error := QDError;
  4355.                   END;
  4356.             END
  4357.          ELSE
  4358.             error := MemError;
  4359.       END
  4360.    ELSE
  4361.       error := MemError;
  4362.    (* Handle any errors along the way *)
  4363.    IF error <> noErr THEN
  4364.       BEGIN
  4365.          IF embryoITab <> NIL THEN
  4366.             DisposHandle(Handle(embryoITab));
  4367.          IF newDevice <> NIL THEN
  4368.             DisposHandle(Handle(newDevice));
  4369.       END
  4370.    ELSE
  4371.       retGDevice := newDevice;
  4372.    (* Return a handle to the new GDevice *)
  4373.    CreateGDevice := error;
  4374. END;
  4375. MPW C Listing 3
  4376. #define kITabRes 4 /* Inverse-table resolution */
  4377. OSErr CreateGDevice(
  4378.     PixMapHandle basePixMap,  /* Handle to the PixMap to base GDevice on */
  4379.     GDHandle     *retGDevice) /* Returns a handle to the new GDevice */
  4380. {
  4381.     GDHandle   newDevice;  /* Handle to the new GDevice */
  4382.     ITabHandle embryoITab; /* Handle to the embryonic inverse table */
  4383.     Rect       deviceRect; /* Rectangle of GDevice */
  4384.     OSErr      error;      /* Error code */
  4385.     /* Initialize a few things before we begin */
  4386.     error = noErr;
  4387.     newDevice = nil;
  4388.     embryoITab = nil;
  4389.     /* Allocate memory for the new GDevice */
  4390.     newDevice = (GDHandle)NewHandle( sizeof (GDevice) );
  4391.     if (newDevice != nil)
  4392.     {
  4393.         /* Allocate the embryonic inverse table */
  4394.         embryoITab = (ITabHandle)NewHandleClear( 2 );
  4395.         if (embryoITab != nil)
  4396.         {
  4397.             /* Set rectangle of device to PixMap bounds */
  4398.             deviceRect = (**basePixMap).bounds;
  4399.             /* Initialize the new GDevice fields */
  4400.             (**newDevice).gdRefNum = 0;            /* Only used for screens */
  4401.             (**newDevice).gdID = 0;                /* Won’t normally use */
  4402.             if ((**basePixMap).pixelSize <= 8)
  4403.                 (**newDevice).gdType = clutType;   /* Depth≤8; clut device */
  4404.             else
  4405.                 (**newDevice).gdType = directType; /* Depth>8; direct device */
  4406.             (**newDevice).gdITable = embryoITab;   /* 2-byte handle for now */
  4407.             (**newDevice).gdResPref = kITabRes;    /* Normal inv table res */
  4408.             (**newDevice).gdSearchProc = nil;      /* No color-search proc */
  4409.             (**newDevice).gdCompProc = nil;        /* No complement proc */
  4410.             (**newDevice).gdFlags = 0;             /* Will set these later */
  4411.             (**newDevice).gdPMap = basePixMap;     /* Reference our PixMap */
  4412.             (**newDevice).gdRefCon = 0;            /* Won’t normally use */
  4413.             (**newDevice).gdNextGD = nil;          /* Not in GDevice list */
  4414.             (**newDevice).gdRect = deviceRect;     /* Use PixMap dimensions */
  4415.             (**newDevice).gdMode = -1;             /* For nonscreens */
  4416.             (**newDevice).gdCCBytes = 0;           /* Only used for screens */
  4417.             (**newDevice).gdCCDepth = 0;           /* Only used for screens */
  4418.             (**newDevice).gdCCXData = 0;           /* Only used for screens */
  4419.             (**newDevice).gdCCXMask = 0;           /* Only used for screens */
  4420.             (**newDevice).gdReserved = 0;          /* Currently unused */
  4421.             /* Set color-device bit if PixMap isn’t black & white */
  4422.             if ((**basePixMap).pixelSize > 1)
  4423.                 SetDeviceAttribute( newDevice, gdDevType, true );
  4424.             /* Set bit to indicate that the GDevice has no video driver */
  4425.             SetDeviceAttribute( newDevice, noDriver, true );
  4426.             /* Initialize the inverse table */
  4427.             if ((**basePixMap).pixelSize <= 8)
  4428.             {
  4429.                 MakeITable( (**basePixMap).pmTable, (**newDevice).gdITable,
  4430.                         (**newDevice).gdResPref );
  4431.                 error = QDError();
  4432.             }
  4433.         }
  4434.         else
  4435.             error = MemError();
  4436.     }
  4437.     else
  4438.         error = MemError();
  4439.     /* Handle any errors along the way */
  4440.     if (error != noErr)
  4441.     {
  4442.         if (embryoITab != nil)
  4443.             DisposHandle( (Handle)embryoITab );
  4444.         if (newDevice != nil)
  4445.             DisposHandle( (Handle)newDevice );
  4446.     }
  4447.     else
  4448.         *retGDevice = newDevice;
  4449.     /* Return a handle to the new GDevice */
  4450.     return error;
  4451. }
  4452. CreateGDevice begins by allocating the GDevice structure and an embryonic form of the inverse table in the current heap. The inverse table is allocated as two zero bytes for now; it’ll be resized and initialized to be a real inverse table later in this routine. Then, each of the GDevice fields are initialized as described earlier.
  4453. After all the fields have been initialized, the gdFlags field is set through _SetDeviceAttribute. If the desired pixel depth is greater than 1, then the gdDevType bit is set. This indicates that the GDevice is for a color graphics environment. This bit should be set even if a gray-scale color table is used for this off-screen graphics environment. The noDriver bit is set because this is an off-screen GDevice and so there’s no associated video device driver.
  4454. Finally, the inverse table is resized and initialized by calling the _MakeITable routine. A handle to the two-byte embryonic inverse table that was created earlier in CreateGDevice is passed as a parameter, as is a handle to the off-screen color table and the preferred inverse-table resolution.
  4455. All Fall Down
  4456. Now that we have a way to create an off-screen graphics environment, there has to be a way to get rid of it too. The DisposeOffScreen routine shown in Listing 4 does this. The CreateOffScreen routine returns an off-screen graphics environment that’s represented by a CGrafPort and GDevice. The DisposeOffScreen routine takes the off-screen CGrafPort and GDevice and deallocates all the memory that’s associated with them including the CGrafPort and its dependent structures, the GDevice, the PixMap, the color table, and the inverse table.
  4457. MPW Pascal Listing 4
  4458. PROCEDURE DisposeOffScreen(
  4459.    doomedPort:    CGrafPtr; {Pointer to the CGrafPort we’re getting rid of}
  4460.    doomedGDevice: GDHandle  {Handle to the GDevice we’re getting rid of}
  4461.    );
  4462.    VAR
  4463.       currPort:    CGrafPtr; {Pointer to the current port}
  4464.       currGDevice: GDHandle; {Handle to the current GDevice}
  4465. BEGIN
  4466.    (* Check to see whether the doomed CGrafPort is the current port *)
  4467.    GetPort(GrafPtr(currPort));
  4468.    IF currPort = doomedPort THEN
  4469.       BEGIN
  4470.          (* It is; set current port to Window Manager CGrafPort *)
  4471.          GetCWMgrPort(currPort);
  4472.          SetPort(GrafPtr(currPort));
  4473.       END;
  4474.    (* Check to see whether the doomed GDevice is the current GDevice *)
  4475.    currGDevice := GetGDevice;
  4476.    IF currGDevice = doomedGDevice THEN
  4477.       (* It is; set current GDevice to the main screen’s GDevice *)
  4478.       SetGDevice(GetMainDevice);
  4479.    (* Throw everything away *)
  4480.    doomedGDevice^^.gdPMap := NIL;
  4481.    DisposGDevice(doomedGDevice);
  4482.    DisposPtr(doomedPort^.portPixMap^^.baseAddr);
  4483.    IF doomedPort^.portPixMap^^.pmTable <> NIL THEN
  4484.       DisposCTable(doomedPort^.portPixMap^^.pmTable);
  4485.    CloseCPort(doomedPort);
  4486.    DisposPtr(Ptr(doomedPort));
  4487. END;
  4488. MPW C Listing 4
  4489. void DisposeOffScreen(
  4490.     CGrafPtr doomedPort,    /* Pointer to the CGrafPort to be disposed of */
  4491.     GDHandle doomedGDevice) /* Handle to the GDevice to be disposed of */
  4492. {
  4493.     CGrafPtr currPort;    /* Pointer to the current port */
  4494.     GDHandle currGDevice; /* Handle to the current GDevice */
  4495.     /* Check to see whether the doomed CGrafPort is the current port */
  4496.     GetPort( (GrafPtr *)&currPort );
  4497.     if (currPort == doomedPort)
  4498.     {
  4499.         /* It is; set current port to Window Manager CGrafPort */
  4500.         GetCWMgrPort( &currPort );
  4501.         SetPort( (GrafPtr)currPort );
  4502.     }
  4503.     /* Check to see whether the doomed GDevice is the current GDevice */
  4504.     currGDevice = GetGDevice();
  4505.     if (currGDevice == doomedGDevice)
  4506.         /* It is; set current GDevice to the main screen’s GDevice */
  4507.         SetGDevice( GetMainDevice() );
  4508.     /* Throw everything away */
  4509.     (**doomedGDevice).gdPMap = nil;
  4510.     DisposGDevice( doomedGDevice );
  4511.     DisposPtr( (**doomedPort->portPixMap).baseAddr );
  4512.     if ((**doomedPort->portPixMap).pmTable != nil)
  4513.         DisposCTable( (**doomedPort->portPixMap).pmTable );
  4514.     CloseCPort( doomedPort );
  4515.     DisposPtr( (Ptr)doomedPort );
  4516. }
  4517. One mildly tricky aspect of this is that we shouldn’t dispose of the current graphics environment. To prevent this, the current port is retrieved by a call to _GetPort. If it returns a pointer to the same port that DisposeOffScreen is disposing, then the current port is set to the Window Manager’s CGrafPort. That was an arbitrary choice, but it’s the most neutral. Similarly, the current GDevice is retrieved by a call to _GetGDevice. If it returns a handle to the same GDevice that DisposeOffScreen is disposing, then the current port is set to the main screen’s GDevice. Again, that’s an arbitrary, neutral choice.
  4518. The inverse table, GDevice, pixel image, and color table are disposed of. Before disposing of the color table, a check is first made to see whether it’s NIL. That’s because it’s reasonable, though not normal, for the PixMap not to have even a dummy color table if the direct-color model is being used. Then the CGrafPort is closed which deallocates all the pieces associated with the CGrafPort, including the PixMap. Once this is done, all the structures that were created by calling CreateOffScreen are deallocated.
  4519. Playing With Blocks
  4520. Now that these four routines with two entry points can create and dispose of off-screen graphics environments, how are they used? There are several phases to using an off-screen graphics environment: creating it, drawing into it, switching between it and other off-screen and on-screen graphics environments, copying images to and from it, and disposing of it. Listing 5 shows a routine called ExerciseOffScreen which is a very basic example of all of these phases.
  4521. MPW Pascal Listing 5
  4522. PROCEDURE ExerciseOffScreen;
  4523.    CONST
  4524.       kOffDepth  = 8;    {Number of bits per pixel in off-screen environment}
  4525.       rGrayClut  = 1600; {Resource ID of gray-scale clut}
  4526.       rColorClut = 1601; {Resource ID of full-color clut}
  4527.    VAR
  4528.       grayPort:    CGrafPtr;   {Graphics environment for gray off screen}
  4529.       grayDevice:  GDHandle;   {Color environment for gray off screen}
  4530.       colorPort:   CGrafPtr;   {Graphics environment for color off screen}
  4531.       colorDevice: GDHandle;   {Color environment for color off screen}
  4532.       savedPort:   GrafPtr;    {Pointer to the saved graphics environment}
  4533.       savedDevice: GDHandle;   {Handle to the saved color environment}
  4534.       offColors:   CTabHandle; {Colors for off-screen environments}
  4535.       offRect:     Rect;       {Rectangle of off-screen environments}
  4536.       circleRect:  Rect;       {Rectangles for circle-drawing}
  4537.       count:       Integer;    {Generic counter}
  4538.       aColor:      RGBColor;   {Color used for drawing off screen}
  4539.       error:       OSErr;      {Error return from off-screen creation}
  4540. BEGIN
  4541.    (* Set up the rectangle for the off-screen graphics environments *)
  4542.    SetRect(offRect, 0, 0, 256, 256);
  4543.    (* Get the color table for the gray off-screen graphics environment *)
  4544.    offColors := GetCTable(rGrayClut);
  4545.    (* Create the gray off-screen graphics environment *)
  4546.    error := CreateOffScreen(offRect, kOffDepth, offColors, grayPort,
  4547.          grayDevice);
  4548.    IF error = noErr THEN
  4549.       BEGIN
  4550.          (* Get the color table for the color off-screen graphics environment *)
  4551.          offColors := GetCTable(rColorClut);
  4552.          (* Create the color off-screen graphics environment *)
  4553.          error := CreateOffScreen(offRect, kOffDepth, offColors, colorPort,
  4554.                colorDevice);
  4555.          IF error = noErr THEN
  4556.             BEGIN
  4557.                (* Save the current graphics environment *)
  4558.                GetPort(savedPort);
  4559.                savedDevice := GetGDevice;
  4560.                (* Set the current graphics environment to the gray one *)
  4561.                SetPort(GrafPtr(grayPort));
  4562.                SetGDevice(grayDevice);
  4563.                (* Draw gray-scale ramp into the gray off-screen environment *)
  4564.                FOR count := 0 TO 255 DO
  4565.                   BEGIN
  4566.                      aColor.red := count * 257;
  4567.                      aColor.green := aColor.red;
  4568.                      aColor.blue := aColor.green;
  4569.                      RGBForeColor(aColor);
  4570.                      MoveTo(0, count);
  4571.                      LineTo(255, count);
  4572.                   END;
  4573.                (* Copy gray ramp into color off-screen colorized with green *)
  4574.                SetPort(GrafPtr(colorPort));
  4575.                SetGDevice(colorDevice);
  4576.                aColor.red := $0000; aColor.green := $FFFF; aColor.blue := $0000;
  4577.                RGBForeColor(aColor);
  4578.                CopyBits(GrafPtr(grayPort)^.portBits,
  4579.                      GrafPtr(colorPort)^.portBits,
  4580.                      grayPort^.portRect,
  4581.                      colorPort^.portRect,
  4582.                      srcCopy + ditherCopy, NIL);
  4583.                (* Draw red, green, and blue circles *)
  4584.                PenSize(8, 8);
  4585.                aColor.red := $FFFF; aColor.green := $0000; aColor.blue := $0000;
  4586.                RGBForeColor(aColor);
  4587.                circleRect := colorPort^.portRect;
  4588.                FrameOval(circleRect);
  4589.                aColor.red := $0000; aColor.green := $FFFF; aColor.blue := $0000;
  4590.                RGBForeColor(aColor);
  4591.                InsetRect(circleRect, 20, 20);
  4592.                FrameOval(circleRect);
  4593.                aColor.red := $0000; aColor.green := $0000; aColor.blue := $FFFF;
  4594.                RGBForeColor(aColor);
  4595.                InsetRect(circleRect, 20, 20);
  4596.                FrameOval(circleRect);
  4597.                (* Copy the color off-screen environment to the current port *)
  4598.                SetPort(savedPort);
  4599.                SetGDevice(savedDevice);
  4600.                CopyBits(GrafPtr(colorPort)^.portBits, savedPort^.portBits,
  4601.                      colorPort^.portRect, savedPort^.portRect,
  4602.                      srcCopy, NIL);
  4603.                (* Dispose of the off-screen graphics environments *)
  4604.                DisposeOffScreen(grayPort, grayDevice);
  4605.                DisposeOffScreen(colorPort, colorDevice);
  4606.             END;
  4607.       END;
  4608. END;
  4609. MPW C Listing 5
  4610. #define kOffDepth  8    /* Number of bits per pixel in off-screen environment */
  4611. #define rGrayClut  1600 /* Resource ID of gray-scale clut */
  4612. #define rColorClut 1601 /* Resource ID of full-color clut */
  4613. void ExerciseOffScreen()
  4614. {
  4615.     CGrafPtr   grayPort;    /* Graphics environment for gray off screen */
  4616.     GDHandle   grayDevice;  /* Color environment for gray off screen */
  4617.     CGrafPtr   colorPort;   /* Graphics environment for color off screen */
  4618.     GDHandle   colorDevice; /* Color environment for color off screen */
  4619.     GrafPtr    savedPort;   /* Pointer to the saved graphics environment */
  4620.     GDHandle   savedDevice; /* Handle to the saved color environment */
  4621.     CTabHandle offColors;   /* Colors for off-screen environments */
  4622.     Rect       offRect;     /* Rectangle of off-screen environments */
  4623.     Rect       circleRect;  /* Rectangles for circle-drawing */
  4624.     short      count;       /* Generic counter */
  4625.     RGBColor   aColor;      /* Color used for drawing off screen */
  4626.     OSErr      error;       /* Error return from off-screen creation */
  4627.     /* Set up the rectangle for the off-screen graphics environments */
  4628.     SetRect( &offRect, 0, 0, 256, 256 );
  4629.     /* Get the color table for the gray off-screen graphics environment */
  4630.     offColors = GetCTable( rGrayClut );
  4631.     /* Create the gray off-screen graphics environment */
  4632.     error = CreateOffScreen( &offRect, kOffDepth, offColors,
  4633.             &grayPort, &grayDevice );
  4634.     if (error == noErr)
  4635.     {
  4636.         /* Get the color table for the color off-screen graphics environment */
  4637.         offColors = GetCTable( rColorClut );
  4638.         /* Create the color off-screen graphics environment */
  4639.         error = CreateOffScreen( &offRect, kOffDepth, offColors,
  4640.                 &colorPort, &colorDevice );
  4641.         if (error == noErr)
  4642.         {
  4643.             /* Save the current graphics environment */
  4644.             GetPort( &savedPort );
  4645.             savedDevice = GetGDevice();
  4646.             /* Set the current graphics environment to the gray one */
  4647.             SetPort( (GrafPtr)grayPort );
  4648.             SetGDevice( grayDevice );
  4649.             /* Draw gray-scale ramp into the gray off-screen environment */
  4650.             for (count = 0; count < 256; ++count)
  4651.             {
  4652.                 aColor.red = aColor.green = aColor.blue = count * 257;
  4653.                 RGBForeColor( &aColor );
  4654.                 MoveTo( 0, count );
  4655.                 LineTo( 255, count );
  4656.             }
  4657.             /* Copy gray ramp into color off-screen colorized with green */
  4658.             SetPort( (GrafPtr)colorPort );
  4659.             SetGDevice( colorDevice );
  4660.             aColor.red = 0x0000; aColor.green = 0xFFFF; aColor.blue = 0x0000;
  4661.             RGBForeColor( &aColor );
  4662.             CopyBits( &((GrafPtr)grayPort)->portBits,
  4663.                     &((GrafPtr)colorPort)->portBits,
  4664.                     &grayPort->portRect,
  4665.                     &colorPort->portRect,
  4666.                     srcCopy | ditherCopy, nil );
  4667.             /* Draw red, green, and blue circles */
  4668.             PenSize( 8, 8 );
  4669.             aColor.red = 0xFFFF; aColor.green = 0x0000; aColor.blue = 0x0000;
  4670.             RGBForeColor( &aColor );
  4671.             circleRect = colorPort->portRect;
  4672.             FrameOval( &circleRect );
  4673.             aColor.red = 0x0000; aColor.green = 0xFFFF; aColor.blue = 0x0000;
  4674.             RGBForeColor( &aColor );
  4675.             InsetRect( &circleRect, 20, 20 );
  4676.             FrameOval( &circleRect );
  4677.             aColor.red = 0x0000; aColor.green = 0x0000; aColor.blue = 0xFFFF;
  4678.             RGBForeColor( &aColor );
  4679.             InsetRect( &circleRect, 20, 20 );
  4680.             FrameOval( &circleRect );
  4681.             /* Copy the color off-screen environment to the current port */
  4682.             SetPort( savedPort );
  4683.             SetGDevice( savedDevice );
  4684.             CopyBits( &((GrafPtr)colorPort)->portBits, &savedPort->portBits,
  4685.                     &colorPort->portRect, &savedPort->portRect,
  4686.                     srcCopy, nil );
  4687.             /* Dispose of the off-screen graphics environments */
  4688.             DisposeOffScreen( grayPort, grayDevice );
  4689.             DisposeOffScreen( colorPort, colorDevice );
  4690.         }
  4691.     }
  4692. }
  4693. Two off-screen graphics environments are created in the same way. A rectangle that’s 256 pixels wide by 256 pixels high and with its top-left coordinate at (0, 0) is created in the offRect local variable. 'clut' resources are loaded from the application’s resource fork to use as the color tables of the two off-screen graphics environments; a gray-scale 'clut' in the first case and a full-color 'clut' in the second case. Then, CreateOffScreen is called with the rectangle, color table, and a hard-coded pixel depth of eight bits per pixel.
  4694. If CreateOffScreen returns noErr in both cases, then the current graphics environment is saved so that it can be restored later. Graphics environments consist of the current port and the current GDevice. The current GrafPort or CGrafPort is saved with _GetPort. The current GDevice is saved with _GetGDevice.
  4695. The gray-scale off-screen graphics environment is set as the current graphics environment by calling _SetPort with its CGrafPort and calling _SetGDevice with its GDevice. A vertical gray ramp is drawn into this graphics environment with the usual set of QuickDraw calls. This graphics environment’s pixel image is then copied to the full-color off-screen graphics environment with dithering and colorization with green (dithering requires 32-Bit QuickDraw and consistent colorization requires system software version 7.0; both of these features are described in Konstantin Othmer’s article “QuickDraw’s CopyBits Procedure: Better Than Ever in System 7.0” in Issue 6 of develop). Before this copy happens, the full-color off-screen graphics environment must be set as the current one. Once this is done, _CopyBits can properly map colors from the gray-scale off-screen graphics environment to the full-color one which gets a green ramp image.
  4696. Red, green, and blue concentric circles are drawn into the full-color off-screen graphics environment over the green ramp. This image is then copied to the graphics environment that was the current one when ExerciseOffScreen was called. To do this, the saved graphics environment is set as the current one by what should now be the familiar calls to _SetPort and _SetGDevice. The off-screen image is then copied to the saved graphics environment with _CopyBits.
  4697. Finally, the two off-screen graphics environments are disposed of by calling the DisposeOffScreen routine that’s defined in the section “All Fall Down”  earlier in this Note.
  4698. Put That Checkbook Away!
  4699. The previous section covered the basics of creating and using off-screen graphics environments. This is good enough for many, if not most, needs of off-screen drawing. But there are variations to creating and maintaining an off-screen graphics environment for specific cases. This section discusses a few of the more common cases.
  4700. About That Creation Thing . . .
  4701. The CreateOffScreen routine, defined in Listing 1, takes three pieces of information: the boundary rectangle, the desired pixel depth, and the desired color table. But there’s much more to these pieces than ExerciseOffScreen shows. This section describes these pieces in more detail.
  4702. The first parameter to CreateOffScreen is a rectangle which determines the size and coordinate system of the off-screen graphics environment. Usually, the top-left corner of the rectangle has the coordinate (0, 0) because it’s usually easiest to draw everything using coordinates that can also be thought of as the horizontal and vertical distance in pixels from the top-left corner of the graphics environment. But in some cases, it’s more convenient to have the (0, 0) coordinate somewhere else, and passing CreateOffScreen a rectangle with a nonzero coordinate in the top-left corner is an easy way to do this. The coordinate system can be translated after the off-screen graphics environment is created by using the _SetOrigin routine that’s described on pages 153 through 155 of Inside Macintosh Volume I.
  4703. Warning:    As Inside Macintosh Volume I, page 154, notes, the clip region of the port “sticks” to the coordinate system when you call _SetOrigin. If _SetOrigin offsets the coordinate system by a large amount, then the clip region might be moved completely outside of the port’s drawing area, and nothing can be drawn into that port. After calling _SetOrigin, you should set the clip region so that you can continue drawing into the port.
  4704. The number of bits per pixel implies the maximum number of available colors in a graphics environment, at least roughly speaking. The relationship between the number of bits per pixel and the number of available colors is discussed in the “Graphics Overview” chapter of Inside Macintosh Volume VI, pages 16-8 through 16-9.
  4705. If an indexed-color graphics environment is being made, then a color table must be passed to CreateOffScreen. In ExerciseOffScreen, the color table is retrieved from a 'clut' resource that’s in the application’s resource fork with a call to _GetCTable. Because CreateOffScreen clones this color table, this 'clut' resource can be purgeable so that it can be thrown out if its memory is needed for other purposes. _GetCTable can also be passed some special constants that tell it to allocate various system color tables that can also be passed to CreateOffScreen. These special constants are described on page 17-18 of the “Color QuickDraw” chapter of Inside Macintosh Volume VI. _GetCTable allocates memory for these system color tables, so they should be disposed of after you’re done with them.
  4706. A color table could also be built from scratch by allocating it with a call to _NewHandle and then initializing it by hand. The ColorTable structure is documented on pages 48 through 49 of Inside Macintosh Volume V. Here’s what each of the fields should be set to:
  4707. ctSeed    identification value. This is an arbitrary value that should be changed any time the contents of the color table change so that the inverse table can be kept current. When Color QuickDraw draws anything, it compares the ctSeed of the color table of the PixMap of the current GDevice against the iTabSeed field of the inverse table of the current GDevice. If they’re the same, then Color QuickDraw uses colors according to that inverse table. If they’re different, then Color QuickDraw first rebuilds the inverse table according to the new color table’s contents and its iTabSeed is set to the value of the new color table’s ctSeed; then the rebuilt inverse table is used.
  4708.     When _CopyBits is called with the srcCopy transfer mode, the ctSeed fields of the source and destination pixel maps are compared. If they’re the same, then _CopyBits simply transfers the source pixels to the destination with no mapping of colors. If they’re different, then _CopyBits checks each entry of the color tables to determine whether they have the same colors for the same pixel values. If they do, then _CopyBits again simply transfers the source pixels to the destination with no mapping of colors. If they don’t, then _CopyBits maps colors in the source PixMap to the colors in the current graphics environment according to the inverse table of the current GDevice. The ctSeed field of a color table should be changed whenever its contents are changed so that _CopyBits doesn’t make the wrong assumptions about the equality of the source and destination color tables.
  4709.     You can get a seed value for a new color table by assigning to it the result of the _GetCTSeed routine, documented in the “Color Manager” chapter of Inside Macintosh Volume V, page 143. If the contents of an existing color table are changed, then it should be passed to the _CTabChanged routine which assigns a new value to its ctSeed field. If the _CTabChanged routine isn’t available (it’s available with 32-Bit QuickDraw and is included with the system beginning with system software version 7.0), then the ctSeed field should be given a new value with another call to _GetCTSeed.
  4710. ctFlags    indicates the Boolean characteristics of a color table. If the most significant bit of ctFlags is clear, then the value field of each ColorSpec entry in the ctTable array is interpreted as the pixel value for the color that’s specified in the rgb field in the same ColorSpec entry. You can build a color table with nonconsecutive pixel values this way. If this bit is set, then all the value fields in the color table are ignored and the index of each ColorSpec record in the ctTable array is that record’s pixel value. It’s your choice whether to clear this bit and set the value fields or set this bit and ignore the value fields; traditionally this bit is clear for off-screen color tables.
  4711.     If the next most significant bit of ctFlags is set, then the value field of each ColorSpec record in the ctTable array is used by _CopyBits as an index into the color palette that’s attached to the destination window, and the rgb field is ignored. This is documented in the “Palette Manager” chapter of Inside Macintosh Volume VI, page 20-17.
  4712.     The other bits are reserved for future use. If you create a color table from scratch, these other bits must be set to zero. If you use a color table that’s generated by the system, then these bits must be preserved.
  4713. ctSize    the number of color table entries minus 1. Normally, this field is set to 1, 3, 15, or 255 for 1-, 2-, 4-, and 8-bits per pixel, respectively. In special cases, it’s reasonable to have less than the maximum number of entries for the pixel depth. For example, a color table for an 8-bit per pixel graphics environment could have just 150 entries, in which case the ctSize field should hold 149. For this case, it’s still important to allocate as much space in the color table for the maximum number of entries for a pixel depth and clear the entries you’re not using to zero because some parts of Color QuickDraw assume the size of a color table based on the pixel depth.
  4714. ctTable    array of colors and pixel values. This table defines all the available colors in the color table and their pixel values. The value field of each ColorSpec record indicates that color’s pixel value if the most significant bit of ctFlags is clear. It’s ignored if the most significant bit of ctFlags is set. The value field is used as an index into a palette if the next most significant bit of ctFlags is set, in which case the rgb field is ignored. See the discussion of the ctFlags field earlier in this Note for more details.
  4715. Warning:    Color QuickDraw’s text-drawing routines assume that the color table of the destination graphics environment has the maximum number of colors for the pixel depth of the graphics environment, and that white is the first entry in the color table and black is the last entry. If these conditions aren’t satisfied, then the resulting image is unpredictable.
  4716. The code fragment in Listing 6 shows how to allocate a 256-entry color table from scratch. Color tables have a variable size, so the _NewHandle call has to calculate the size of the ColorTable record plus the maximum number of color table entries for the pixel depth multiplied by the size of a ColorSpec record. kNumColors - 1 is used in the calculation because the size of the ColorTable record includes the size of one ColorSpec entry in most development environments.
  4717. MPW Pascal Listing 6
  4718. CONST
  4719.    kNumColors = 256; {Number of color table entries}
  4720. VAR
  4721.    newColors: CTabHandle; {Handle to the new color table}
  4722.    index:     Integer;    {Index into the table of colors}
  4723. (* Allocate memory for the color table *)
  4724. newColors := CTabHandle(NewHandleClear(SizeOf (ColorTable) +
  4725.       SizeOf(ColorSpec) * (kNumColors - 1)));
  4726. IF newColors <> NIL THEN
  4727.    BEGIN
  4728.       (* Initialize the fields *)
  4729.       newColors^^.ctSeed := GetCTSeed;
  4730.       newColors^^.ctFlags := 0;
  4731.       newColors^^.ctSize := kNumColors - 1;
  4732.       (* Initialize the table of colors *)
  4733.       FOR index := 0 TO kNumColors - 1 DO
  4734.          BEGIN
  4735.             newColors^^.ctTable[index].value := index;
  4736.             newColors^^.ctTable[index].rgb.red := someRedValue;
  4737.             newColors^^.ctTable[index].rgb.green := someGreenValue;
  4738.             newColors^^.ctTable[index].rgb.blue := someBlueValue
  4739.          END
  4740.    END
  4741. MPW C Listing 6
  4742. #define kNumColors 256 /* Number of color table entries */
  4743. CTabHandle newColors; /* Handle to the new color table */
  4744. short      index;     /* Index into the table of colors */
  4745. /* Allocate memory for the color table */
  4746. newColors = (CTabHandle)NewHandleClear( sizeof (ColorTable) +
  4747.         sizeof (ColorSpec) * (kNumColors - 1) );
  4748. if (newColors != nil)
  4749. {
  4750.     /* Initialize the fields */
  4751.     (**newColors).ctSeed = GetCTSeed();
  4752.     (**newColors).ctFlags = 0;
  4753.     (**newColors).ctSize = kNumColors - 1;
  4754.     /* Initialize the table of colors */
  4755.     for (index = 0; index < kNumColors; index++)
  4756.     {
  4757.         (**newColors).ctTable[index].value = index;
  4758.         (**newColors).ctTable[index].rgb.red = someRedValue;
  4759.         (**newColors).ctTable[index].rgb.green = someGreenValue;
  4760.         (**newColors).ctTable[index].rgb.blue = someBlueValue;
  4761.     }
  4762. }
  4763. Changing Your Environment
  4764. After you create an off-screen graphics environment with certain dimensions, you might later want to change its size, depth, or color table without creating a completely new graphics environment from scratch and without needing to redraw the existing image. The UpdateOffScreen routine in Listing 7 shows just one way to do this. It takes the same parameters that CreateOffScreen (defined in Listing 1) does, but instead of creating a new CGrafPort and GDevice, it alters the ones that you pass through the updPort and updGDevice parameters. If the newBounds parameter specifies an empty rectangle, then the existing boundary rectangle for the off-screen graphics environment is used. Similarly, if newDepth is zero, then the existing depth is used; and if the newColors parameter is NIL, then the existing color table is used. UpdateOffScreen alters the given CGrafPort and GDevice to the new settings, but it completely replaces the PixMap. After all the alterations are made, the old PixMap’s image is copied to the new PixMap’s image, and then the old PixMap and its image are disposed.
  4765. MPW Pascal Listing 7
  4766. FUNCTION UpdateOffScreen(
  4767.    newBounds:  Rect;       {New bounding rectangle of off-screen}
  4768.    newDepth:   Integer;    {New number of bits per pixel in off-screen}
  4769.    newColors:  CTabHandle; {New color table to assign to off-screen}
  4770.    updPort:    CGrafPtr;   {Returns a pointer to the updated CGrafPort}
  4771.    updGDevice: GDHandle    {Returns a handle to the updated GDevice}
  4772.    ): OSErr;
  4773.    CONST
  4774.       kMaxRowBytes = $3FFE; {Maximum number of bytes per row of pixels}
  4775.    VAR
  4776.       newPixMap:   PixMapHandle; {Handle to the new off-screen PixMap}
  4777.       oldPixMap:   PixMapHandle; {Handle to the old off-screen PixMap}
  4778.       bounds:      Rect;         {Boundary rectangle of off-screen}
  4779.       depth:       Integer;      {Depth of the off-screen PixMap}
  4780.       bytesPerRow: Integer;      {Number of bytes per row in the PixMap}
  4781.       colors:      CTabHandle;   {Colors for the off-screen PixMap}
  4782.       savedFore:   RGBColor;     {Saved foreground color}
  4783.       savedBack:   RGBColor;     {Saved background color}
  4784.       aColor:      RGBColor;     {Used to set foreground and background color}
  4785.       qdVersion:   LongInt;      {Version of QuickDraw currently in use}
  4786.       savedPort:   GrafPtr;      {Pointer to GrafPort used for save/restore}
  4787.       savedDevice: GDHandle;     {Handle to GDevice used for save/restore}
  4788.       savedState:  SignedByte;   {Saved state of color table handle}
  4789.       error:       OSErr;        {Returns error code}
  4790. BEGIN
  4791.    (* Initialize a few things before we begin *)
  4792.    newPixMap := NIL;
  4793.    error := noErr;
  4794.    (* Keep the old bounds rectangle, or get the new one *)
  4795.    IF EmptyRect(newBounds) THEN
  4796.       bounds := updPort^.portRect
  4797.    ELSE
  4798.       bounds := newBounds;
  4799.    (* Keep the old depth, or get the old one *)
  4800.    IF newDepth = 0 THEN
  4801.       depth := updPort^.portPixMap^^.pixelSize
  4802.    ELSE
  4803.       depth := newDepth;
  4804.    (* Get the old clut, or save new clut’s state and make it nonpurgeable *)
  4805.    IF newColors = NIL THEN
  4806.       colors := updPort^.portPixMap^^.pmTable
  4807.    ELSE
  4808.       BEGIN
  4809.          savedState := HGetState(Handle(newColors));
  4810.          HNoPurge(Handle(newColors));
  4811.          colors := newColors;
  4812.       END;
  4813.    (* Calculate the number of bytes per row in the off-screen PixMap *)
  4814.    bytesPerRow := ((depth * (bounds.right - bounds.left) + 31) DIV 32) * 4;
  4815.    (* Get the current QuickDraw version *)
  4816.    error := Gestalt (gestaltQuickdrawVersion, qdVersion);
  4817.    error := noErr;
  4818.    (* Make sure depth is indexed or depth is direct and 32-Bit QD installed *)
  4819.    IF (depth = 1) OR (depth = 2) OR (depth = 4) OR (depth = 8) OR
  4820.          (((depth = 16) OR (depth = 32)) AND (qdVersion >= gestalt32BitQD)) THEN
  4821.       BEGIN
  4822.          (* Maximum number of bytes per row is 16,382; make sure within range *)
  4823.          IF bytesPerRow <= kMaxRowBytes THEN
  4824.             BEGIN
  4825.                (* Make sure a color table is provided if the depth is indexed *)
  4826.                IF depth <= 8 THEN
  4827.                   IF colors = NIL THEN
  4828.                      (* Indexed depth and clut is NIL; is parameter error *)
  4829.                      error := paramErr;
  4830.             END
  4831.          ELSE
  4832.             (* # of bytes per row is more than 16,382; is parameter error *)
  4833.             error := paramErr;
  4834.       END
  4835.    ELSE
  4836.       (* Pixel depth isn’t valid; is parameter error *)
  4837.       error := paramErr;
  4838.    (* If sanity checks succeed, attempt to update the graphics environment *)
  4839.    IF error = noErr THEN
  4840.       BEGIN
  4841.          (* Allocate a new PixMap *)
  4842.          newPixMap := PixMapHandle(NewHandleClear(SizeOf(PixMap)));
  4843.          IF newPixMap <> NIL THEN
  4844.               BEGIN
  4845.                (* Initialize the new PixMap for off-screen drawing *)
  4846.                error := SetUpPixMap(depth, bounds, colors, bytesPerRow,
  4847.                      newPixMap);
  4848.                IF error = noErr THEN
  4849.                   BEGIN
  4850.                      (* Save old PixMap and install new, initialized one *)
  4851.                      oldPixMap := updPort^.portPixMap;
  4852.                      updPort^.portPixMap := newPixMap;
  4853.                      (* Save current port & GDevice; set ones we’re updating *)
  4854.                      GetPort(savedPort);
  4855.                      savedDevice := GetGDevice;
  4856.                      SetPort(GrafPtr(updPort));
  4857.                      SetGDevice(updGDevice);
  4858.                      (* Set portRect, visRgn, clipRgn to given bounds rect *)
  4859.                      updPort^.portRect := bounds;
  4860.                      RectRgn(updPort^.visRgn, bounds);
  4861.                      ClipRect(bounds);
  4862.                      (* Update the GDevice *)
  4863.                      IF newPixMap^^.pixelSize <= 8 THEN
  4864.                         updGDevice^^.gdType := clutType
  4865.                      ELSE
  4866.                         updGDevice^^.gdType := directType;
  4867.                      updGDevice^^.gdPMap := newPixMap;
  4868.                      updGDevice^^.gdRect := newPixMap^^.bounds;
  4869.                      (* Set color-device bit if PixMap isn’t black & white *)
  4870.                      IF newPixMap^^.pixelSize > 1 THEN
  4871.                         SetDeviceAttribute(updGDevice, gdDevType, TRUE);
  4872.                      else
  4873.                         SetDeviceAttribute(updGDevice, gdDevType, FALSE);
  4874.                      (* Save current fore/back colors and set to B&W *)
  4875.                      GetForeColor(savedFore);
  4876.                      GetBackColor(savedBack);
  4877.                      aColor.red := 0; aColor.green := 0; aColor.blue := 0;
  4878.                      RGBForeColor(aColor);
  4879.                      aColor.red := $FFFF;
  4880.                      aColor.green := $FFFF;
  4881.                      aColor.blue := $FFFF;
  4882.                      RGBBackColor(aColor);
  4883.                      (* Copy old image to the new graphics environment *)
  4884.                      HLock(Handle(oldPixMap));
  4885.                      CopyBits(BitMapPtr(oldPixMap^)^, GrafPtr(updPort)^.portBits,
  4886.                            oldPixMap^^.bounds, updPort^.portRect,
  4887.                            srcCopy, NIL);
  4888.                      HUnlock(Handle(oldPixMap));
  4889.                      (* Restore the foreground/background color *)
  4890.                      RGBForeColor(savedFore);
  4891.                      RGBBackColor(savedBack);
  4892.                      (* Restore the saved port *)
  4893.                      SetPort(savedPort);
  4894.                      SetGDevice(savedDevice);
  4895.                      (* Get rid of the old PixMap and its dependents *)
  4896.                      DisposPtr(oldPixMap^^.baseAddr);
  4897.                      DisposeCTable(oldPixMap^^.pmTable);
  4898.                      DisposHandle(Handle(oldPixMap));
  4899.                   END;
  4900.             END
  4901.          ELSE
  4902.               error := MemError;
  4903.      END;
  4904.    (* Restore the given state of the color table *)
  4905.    IF colors <> NIL THEN
  4906.       HSetState(Handle(colors), savedState);
  4907.    (* One Last Look Around The House Before We Go… *)
  4908.    IF error <> noErr THEN
  4909.       BEGIN
  4910.          IF newPixMap <> NIL THEN
  4911.             BEGIN
  4912.                IF newPixMap^^.pmTable <> NIL THEN
  4913.                   DisposCTable(newPixMap^^.pmTable);
  4914.                IF newPixMap^^.baseAddr <> NIL THEN
  4915.                   DisposPtr(newPixMap^^.baseAddr);
  4916.                DisposHandle(Handle(newPixMap));
  4917.             END;
  4918.       END;
  4919.    UpdateOffScreen := error;
  4920. END;
  4921. MPW C Listing 7
  4922. #define kMaxRowBytes 0x3FFE /* Maximum number of bytes in a row of pixels */
  4923. OSErr UpdateOffScreen(
  4924.     Rect       *newBounds, /* New bounding rectangle of off-screen */
  4925.     short      newDepth,   /* New number of bits per pixel in off-screen */
  4926.     CTabHandle newColors,  /* New color table to assign to off-screen */
  4927.     CGrafPtr   updPort,    /* Returns a pointer to the updated CGrafPort */
  4928.     GDHandle   updGDevice) /* Returns a handle to the updated GDevice */
  4929. {
  4930.     PixMapHandle newPixMap;   /* Handle to the new off-screen PixMap */
  4931.     PixMapHandle oldPixMap;   /* Handle to the old off-screen PixMap */
  4932.     Rect         bounds;      /* Boundary rectangle of off-screen */
  4933.     short        depth;       /* Depth of the off-screen PixMap */
  4934.     short        bytesPerRow; /* Number of bytes per row in the PixMap */
  4935.     CTabHandle   colors;      /* Colors for the off-screen PixMap */
  4936.     RGBColor     savedFore;   /* Saved foreground color */
  4937.     RGBColor     savedBack;   /* Saved background color */
  4938.     RGBColor     aColor;      /* Used to set foreground and background color */
  4939.     long         qdVersion;   /* Version of QuickDraw currently in use */
  4940.     GrafPtr      savedPort;   /* Pointer to GrafPort used for save/restore */
  4941.     GDHandle     savedDevice; /* Handle to GDevice used for save/restore */
  4942.     SignedByte   savedState;  /* Saved state of color table handle */
  4943.     OSErr        error;       /* Returns error code */
  4944.     /* Initialize a few things before we begin */
  4945.     newPixMap = nil;
  4946.     error = noErr;
  4947.     /* Keep the old bounds rectangle, or get the new one */
  4948.     if (EmptyRect( newBounds ))
  4949.         bounds = updPort->portRect;
  4950.     else
  4951.         bounds = *newBounds;
  4952.     /* Keep the old depth, or get the old one */
  4953.     if (newDepth == 0)
  4954.         depth = (**updPort->portPixMap).pixelSize;
  4955.     else
  4956.         depth = newDepth;
  4957.     /* Get the old clut, or save new clut’s state and make it nonpurgeable */
  4958.     if (newColors == nil)
  4959.         colors = (**updPort->portPixMap).pmTable;
  4960.     else
  4961.     {
  4962.         savedState = HGetState( (Handle)newColors );
  4963.         HNoPurge( (Handle)newColors );
  4964.         colors = newColors;
  4965.     }
  4966.     /* Calculate the number of bytes per row in the off-screen PixMap */
  4967.     bytesPerRow = ((depth * (bounds.right - bounds.left) + 31) >> 5) << 2;
  4968.     /* Get the current QuickDraw version */
  4969.     (void)Gestalt( gestaltQuickdrawVersion, &qdVersion );
  4970.     /* Make sure depth is indexed or depth is direct and 32-Bit QD installed */
  4971.     if (depth == 1 || depth == 2 || depth == 4 || depth == 8 ||
  4972.             ((depth == 16 || depth == 32) && qdVersion >= gestalt32BitQD))
  4973.     {
  4974.         /* Maximum number of bytes per row is 16,382; make sure within range */
  4975.         if (bytesPerRow <= kMaxRowBytes)
  4976.         {
  4977.             /* Make sure a color table is provided if the depth is indexed */
  4978.             if (depth <= 8)
  4979.                 if (colors == nil)
  4980.                     /* Indexed depth and clut is NIL; is parameter error */
  4981.                     error = paramErr;
  4982.         }
  4983.         else
  4984.             /* # of bytes per row is more than 16,382; is parameter error */
  4985.             error = paramErr;
  4986.     }
  4987.     else
  4988.         /* Pixel depth isn’t valid; is parameter error */
  4989.         error = paramErr;
  4990.     /* If sanity checks succeed, attempt to create a new graphics environment */
  4991.     if (error == noErr)
  4992.     {
  4993.         /* Allocate a new PixMap */
  4994.         newPixMap = (PixMapHandle)NewHandleClear( sizeof (PixMap) );
  4995.         if (newPixMap != nil)
  4996.         {
  4997.             /* Initialize the new PixMap for off-screen drawing */
  4998.             error = SetUpPixMap( depth, &bounds, colors, bytesPerRow, newPixMap );
  4999.             if (error == noErr)
  5000.             {
  5001.                 /* Save the old PixMap and install the new, initialized one */
  5002.                 oldPixMap = updPort->portPixMap;
  5003.                 updPort->portPixMap = newPixMap;
  5004.                 /* Save current port & GDevice and set ones we’re updating */
  5005.                 GetPort( &savedPort );
  5006.                 savedDevice = GetGDevice();
  5007.                 SetPort( (GrafPtr)updPort );
  5008.                 SetGDevice( updGDevice );
  5009.                 /* Set portRect, visRgn, and clipRgn to the given bounds rect */
  5010.                 updPort->portRect = bounds;
  5011.                 RectRgn( updPort->visRgn, &bounds );
  5012.                 ClipRect( &bounds );
  5013.                 /* Update the GDevice */
  5014.                 if ((**newPixMap).pixelSize <= 8)
  5015.                     (**updGDevice).gdType = clutType;
  5016.                 else
  5017.                     (**updGDevice).gdType = directType;
  5018.                 (**updGDevice).gdPMap = newPixMap;
  5019.                 (**updGDevice).gdRect = (**newPixMap).bounds;
  5020.                 /* Set color-device bit if PixMap isn’t black & white */
  5021.                 if ((**newPixMap).pixelSize > 1)
  5022.                     SetDeviceAttribute( updGDevice, gdDevType, true );
  5023.                 else
  5024.                     SetDeviceAttribute( updGDevice, gdDevType, false );
  5025.                 /* Save current foreground/background colors and set to B&W */
  5026.                 GetForeColor( &savedFore );
  5027.                 GetBackColor( &savedBack );
  5028.                 aColor.red = aColor.green = aColor.blue = 0;
  5029.                 RGBForeColor( &aColor );
  5030.                 aColor.red = aColor.green = aColor.blue = 0xFFFF;
  5031.                 RGBBackColor( &aColor );
  5032.                 /* Copy old image to the new graphics environment */
  5033.                 HLock( (Handle)oldPixMap );
  5034.                 CopyBits( (BitMapPtr)*oldPixMap, &((GrafPtr) updPort)->portBits,
  5035.                         &(**oldPixMap).bounds, &updPort->portRect,
  5036.                         srcCopy, nil );
  5037.                 HUnlock( (Handle)oldPixMap );
  5038.                 /* Restore the foreground/background color */
  5039.                 RGBForeColor( &savedFore );
  5040.                 RGBBackColor( &savedBack );
  5041.                 /* Restore the saved port */
  5042.                 SetPort( savedPort );
  5043.                 SetGDevice( savedDevice );
  5044.                 /* Get rid of the old PixMap and its dependents */
  5045.                 DisposPtr( (**oldPixMap).baseAddr );
  5046.                 DisposeCTable( (**oldPixMap).pmTable ) ;
  5047.                 DisposHandle( (Handle)oldPixMap );
  5048.             }
  5049.         }
  5050.         else
  5051.             error = MemError();
  5052.     }
  5053.     /* Restore the given state of the color table */
  5054.     if (colors != nil)
  5055.         HSetState( (Handle)colors, savedState );
  5056.     /* One Last Look Around The House Before We Go… */
  5057.     if (error != noErr)
  5058.     {
  5059.         /* Some error occurred; dispose of everything we allocated */
  5060.         if (newPixMap != nil)
  5061.         {
  5062.             if ((**newPixMap).pmTable)
  5063.                 DisposCTable( (**newPixMap).pmTable );
  5064.             if ((**newPixMap).baseAddr)
  5065.                 DisposPtr ( (**newPixMap).baseAddr );
  5066.             DisposHandle( (Handle)newPixMap );
  5067.         }
  5068.     }
  5069.     return error;
  5070. }
  5071. UpdateOffScreen begins by checking the boundary rectangle, depth, or color table for emptiness, zero, or NIL, respectively. If any these satisfy that condition, then the existing characteristic is used. Next, the same sanity check that CreateOffScreen uses is done. If this sanity check succeeds, then a new PixMap is allocated, and then it’s initialized by the SetUpPixMap routine that’s given in Listing 2 which gives the new PixMap a new pixel image and its own copy of the color table. This new PixMap is installed into the CGrafPort after saving the reference to the old PixMap. Then, the portRect, visRgn, and clipRgn of the CGrafPort are set to the new boundary rectangle, as is the gdRect of the GDevice. The gdType of the GDevice is set either for the indexed-color or direct-color model, the gdPMap is set to the new PixMap, and the device attributes are set according to the pixel depth. Details about the settings for the CGrafPort and GDevice are in “Building the CGrafPort” and “Building the GDevice,” respectively, earlier in this Note.
  5072. At this point, the off-screen graphics environment is ready with its new characteristics, but it has garbage for an image because nothing has been drawn into it yet. The old PixMap, pixel image, and color table are still around, so _CopyBits transfers the old image into the altered graphics environment. _CopyBits handles the mapping from the old image’s characteristics to the new characteristics, so the altered graphics environment gets the best possible representation of the old image according to its new characteristics.
  5073. Changing the Off-Screen Color Table
  5074. Sometimes, it’s useful to change some or all of the colors in an off-screen color table, or to replace the off-screen color table with another one, so that the existing image in an indexed-color graphics environment appears with new colors. For example, if you had an off-screen image of a blue car and wanted to see what it looked like in green, you could change all of the shades of blue in the off-screen color table to green, and then _CopyBits the image to the screen. Notice that this is different from calling the UpdateOffScreen routine in the previous section with a different color table. That routine tries to reproduce the colors from the original image as best it can in the new set of colors. This section discusses the case in which you want the image’s colors to change.
  5075. The most obvious part of doing this is simply to get the color table from the off-screen pixel map’s pmTable field and modify the entries, or to dispose of the off-screen graphics environment’s current color table and assign the new one to it. There’s one more step to complete the process though. The discussion about GDevice records in “The Building Blocks” in this Note discusses inverse tables and how they go hand-in-hand with color tables. If you alter or replace the color table, you have to make sure that the inverse table of the off-screen drawing environment is rebuilt according to the new colors because Color QuickDraw uses that inverse table to know what pixel values to use for the specified color. You don’t have to rebuild the inverse table explicitly as long as you tell Color QuickDraw that the color table changed. To do this, all you have to do is make sure that the ctSeed of the changed or altered color table is set to a new value. And to do this, you can simply call _CTabChanged, which is documented on page 17-26 of the “Color QuickDraw” chapter of Inside Macintosh Volume VI. _CTabChanged is available beginning with 32-Bit QuickDraw and it’s available in system software version 7.0. If this routine isn’t available, then you can still tell Color QuickDraw that the color table has been changed by calling _GetCTSeed and assigning its result directly to your new color table’s ctSeed field.
  5076. The next time you draw into this off-screen drawing environment, Color QuickDraw checks the ctSeed of the environment’s color table against the iTabSeed of the inverse table of the environment’s GDevice. Because you changed the ctSeed of the color table either through _CTabChanged or _GetCTSeed, these two seeds are different so Color QuickDraw automatically rebuilds the inverse table of the current GDevice and then it copies the ctSeed of the color table to the iTabSeed of the rebuilt inverse table. Then drawing continues normally.
  5077. Follow That Screen!
  5078. One common need of off-screen graphics environments is that they have a depth and color table that matches a screen. The CreateOffScreen routine requires a color table for indexed-color environments, and a pixel depth. Because there can be more than one screen attached to a Macintosh system, you have to decide which screen’s depth and color table you should use. Typically, the depth and color table of the deepest screen that contains the area that you’re interested in (probably the area of a window) is used. Another option is to use the depth and color table of the screen that has the largest area of intersection with the area that you’re interested in. To find the depth and color table of the screen on which you want to base an off-screen graphics environment, you must use the list of graphics devices for all screens which is maintained by the system. Every GDevice record for a screen has a handle to that screen’s PixMap, and you can find the screen’s depth and color table there.
  5079. Listing 8 shows a routine called CreateScreenOffScreen which creates an off-screen graphics environment that has the depth and color table of a selected screen. The first parameter, bounds, specifies the rectangular part of the screen area in which you’re interested in global coordinates. The screenOption parameter specifies how you want the screen to be chosen. If you pass kDeepestScreen in this parameter, CreateScreenOffScreen creates the new off-screen graphics environment with the depth and color table of the deepest screen that intersects the bounds rectangle. If you instead pass kLargestScreenArea, then the new off-screen graphics environment is created with the depth and color table of the screen with the largest area of intersection with the bounds rectangle.
  5080. MPW Pascal Listing 8
  5081. TYPE
  5082.    ScreenOpt = (kDeepestScreen, kLargestAreaScreen);
  5083. FUNCTION CreateScreenOffScreen(
  5084.    bounds:         Rect;      {Global rectangle of part of screen to save}
  5085.    screenOption:   ScreenOpt; {Use deepest or largest intersection area screen?}
  5086.    VAR retPort:    CGrafPtr;  {Returns a pointer to the new CGrafPort}
  5087.    VAR retGDevice: GDHandle   {Returns a handle to the new GDevice}
  5088.    ): OSErr;
  5089.    VAR
  5090.       baseGDevice:  GDHandle;     {GDevice to base off-screen on}
  5091.       aGDevice:     GDHandle;     {Handle to each GDevice in the GDevice list}
  5092.       basePixMap:   PixMapHandle; {baseGDevice’s PixMap}
  5093.       maxArea:      LongInt;      {Largest intersection area found}
  5094.       area:         LongInt;      {Area of rectangle of intersection}
  5095.       commonRect:   Rect;         {Rectangle of intersection}
  5096.       normalBounds: Rect;         {bounds rectangle normalized to (0, 0)}
  5097.       error:        Integer;      {Error code}
  5098. BEGIN
  5099.    error := noErr;
  5100.    (* Different screen options require different algorithms *)
  5101.    IF screenOption = kDeepestScreen THEN
  5102.       (* Graphics Devices Manager tells us the deepest intersecting screen *)
  5103.       baseGDevice := GetMaxDevice(bounds)
  5104.    ELSE IF screenOption = kLargestAreaScreen THEN
  5105.       BEGIN
  5106.          (* Get a handle to the first GDevice in the GDevice list *)
  5107.          aGDevice := GetDeviceList;
  5108.     
  5109.          (* Keep looping until all GDevices have been checked *)
  5110.          maxArea := 0;
  5111.          baseGDevice := NIL;
  5112.          WHILE aGDevice <> NIL DO
  5113.             BEGIN
  5114.                (* Check to see whether screen rectangle and bounds intersect *)
  5115.                IF SectRect(aGDevice^^.gdRect, bounds, commonRect) THEN
  5116.                   BEGIN
  5117.                      (* Calculate area of intersection *)
  5118.                      area := LongInt(commonRect.bottom - commonRect.top) *
  5119.                            LongInt(commonRect.right - commonRect.left);
  5120.                      (* Keep track of largest area of intersection so far *)
  5121.                      IF area > maxArea THEN
  5122.                         BEGIN
  5123.                            maxArea := area;
  5124.                            baseGDevice := aGDevice;
  5125.                         END;
  5126.                   END;
  5127.                (* Go to the next GDevice in the GDevice list *)
  5128.                aGDevice := GetNextDevice(aGDevice);
  5129.             END;
  5130.       END
  5131.    ELSE
  5132.       error := paramErr;
  5133.    (* If no screens intersect the bounds, baseDevice is NIL *)
  5134.    IF (baseGDevice <> NIL) AND (error = noErr) THEN
  5135.       BEGIN
  5136.          (* Normalize the bounds rectangle *)
  5137.          normalBounds := bounds;
  5138.          OffsetRect(normalBounds, -normalBounds.left, -normalBounds.top);
  5139.          (* Create off-screen graphics environment w/ depth, clut of screen *)
  5140.          basePixMap := baseGDevice^^.gdPMap;
  5141.          error := CreateOffScreen(normalBounds, basePixMap^^.pixelSize,
  5142.                basePixMap^^.pmTable, retPort, retGDevice);
  5143.       END;
  5144.    CreateScreenOffScreen := error;
  5145. END;
  5146. MPW C Listing 8
  5147. enum
  5148. {
  5149.     kDeepestScreen,
  5150.     kLargestAreaScreen,
  5151. };
  5152. OSErr CreateScreenOffScreen(
  5153.     Rect     *bounds,      /* Global rectangle of part of screen to save */
  5154.     short    screenOption, /* Use deepest or largest intersection area screen */
  5155.     CGrafPtr *retPort,     /* Returns a pointer to the new CGrafPort */
  5156.     GDHandle *retGDevice)  /* Returns a handle to the new GDevice */
  5157. {
  5158.     GDHandle     baseGDevice;  /* GDevice to base off-screen on */
  5159.     GDHandle     aGDevice;     /* Handle to each GDevice in the GDevice list */
  5160.     PixMapHandle basePixMap;   /* baseGDevice’s PixMap */
  5161.     long         maxArea;      /* Largest intersection area found */
  5162.     long         area;         /* Area of rectangle of intersection */
  5163.     Rect         commonRect;   /* Rectangle of intersection */
  5164.     Rect         normalBounds; /* bounds rectangle normalized to (0, 0) */
  5165.     short        error;        /* Error code */
  5166.     error = noErr;
  5167.     /* Different screen options require different algorithms */
  5168.     if (screenOption == kDeepestScreen)
  5169.         /* Graphics Devices Manager tells us the deepest intersecting screen */
  5170.         baseGDevice = GetMaxDevice( bounds );
  5171.     else if (screenOption == kLargestAreaScreen)
  5172.     {
  5173.         /* Get a handle to the first GDevice in the GDevice list */
  5174.         aGDevice = GetDeviceList();
  5175.     
  5176.         /* Keep looping until all GDevices have been checked */
  5177.         maxArea = 0;
  5178.         baseGDevice = nil;
  5179.         while (aGDevice != nil)
  5180.         {
  5181.             /* Check to see whether screen rectangle and bounds intersect */
  5182.             if (SectRect( &(**aGDevice).gdRect, bounds, &commonRect ))
  5183.             {
  5184.                 /* Calculate area of intersection */
  5185.                 area = (long)(commonRect.bottom - commonRect.top) *
  5186.                        (long)(commonRect.right - commonRect.left);
  5187.                 /* Keep track of largest area of intersection found so far */
  5188.                 if (area > maxArea)
  5189.                 {
  5190.                     maxArea = area;
  5191.                     baseGDevice = aGDevice;
  5192.                 }
  5193.             }
  5194.             /* Go to the next GDevice in the GDevice list */
  5195.             aGDevice = GetNextDevice( aGDevice );
  5196.         }
  5197.     }
  5198.     else
  5199.         error = paramErr;
  5200.     /* If no screens intersect the bounds, baseDevice is NIL */
  5201.     if (baseGDevice != nil && error == noErr)
  5202.     {
  5203.         /* Normalize the bounds rectangle */
  5204.         normalBounds = *bounds;
  5205.         OffsetRect( &normalBounds, -normalBounds.left, -normalBounds.top );
  5206.         /* Create off-screen graphics environment w/ depth, clut of screen */
  5207.         basePixMap = (**baseGDevice).gdPMap;
  5208.         error = CreateOffScreen( &normalBounds, (**basePixMap).pixelSize,
  5209.                 (**basePixMap).pmTable, retPort, retGDevice );
  5210.     }
  5211.     return error;
  5212. }
  5213. Finding the deepest screen that intersects an on-screen area is trivially easy because there’s a Graphics Devices Manager routine that finds it called _GetMaxDevice which is documented on page 21-22 of the “Graphics Devices Manager” chapter of Inside Macintosh Volume VI. The rectangle in global coordinates of the screen area you’re interested in is passed to _GetMaxDevice, and it returns a handle to the deepest screen that intersects that area, even if the area of intersection is as small as one pixel. If no screens intersect that area, then _GetMaxDevice returns NIL.
  5214. Finding the GDevice of the screen that has the maximum area of intersection with the screen area you’re interested in isn’t quite so easy because there’s no single Graphics Devices Manager routine to find this GDevice; you have to search the GDevice list yourself. You can get a handle to the first GDevice in the list by calling _GetDeviceList, and you can get a handle to each successive GDevice by calling _GetNextDevice. _GetDeviceList is documented on pages 21-21 through 21-22 of the “Graphics Devices Manager” chapter of Inside Macintosh Volume VI, and _GetNextDevice is documented on page 21-22 of the same chapter. For each GDevice in the list, the area of intersection between the bounds and the gdRect of the GDevice is calculated. If the calculated area is the largest area of intersection found so far, then that area and the GDevice of that screen are remembered.
  5215. Once a winning GDevice has been chosen, either by being the deepest intersecting GDevice or the GDevice with the largest intersecting area, then CreateOffScreen routine is called with the pixel depth and color table of the PixMap of the GDevice, and the bounds rectangle normalized so that its top-left coordinate has the coordinates (0, 0). CreateOffScreen returns with the new off-screen graphics environment, and CreateScreenOffScreen returns this to the caller.
  5216. Choosing Your Off-Screen Memory
  5217. The CreateOffScreen routine in Listing 1 creates an off-screen graphics environment with its pixel image allocated as a nonrelocatable block in the application’s heap. But this isn’t the only way that the pixel image can be allocated. Pixel images can be big, and big blocks of nonrelocatable memory in your heap can be expensive in terms of performance, and they can cause a bad case of heap fragmentation. Why not put the pixel image in a relocatable block of memory instead? If there isn’t much free memory in your heap and if MultiFinder or system software version 7.0 is running, there’s memory that’s not being used by any open applications, called temporary memory (formerly called MultiFinder temporary memory). Why not use this area of memory for the pixel image? Some people have NuBus cards with plenty of memory on them. Why not move the pixel image out of the heaps altogether and instead use NuBus memory for the pixel image? All of these things can be done with simple modifications to what’s been discussed in this Note, and these modifications are discussed in the next few paragraphs.
  5218. How can pixel images be relocatable? After all, pixel images are referred to only by the baseAddr field of a PixMap, and the baseAddr is a pointer, not a handle. It’s true that while QuickDraw is being used to draw into a graphics environment, the pixel image had better not move or else QuickDraw will start drawing over the area of memory that the pixel image used to be rather than where it is. But if QuickDraw isn’t doing anything with the graphics environment, then it doesn’t care what happens to the pixel image as long as the baseAddr points to it once QuickDraw starts drawing into the graphics environment. This implies a strategy: allocate the pixel image as a relocatable block and let it float in the heap; when QuickDraw is about to to draw into the graphics environment or to copy from it, lock the pixel image and copy its master pointer into the baseAddr field of the PixMap; when the drawing or copying is finished, unlock the pixel image. There are many ways to implement this, and Listing 9 shows a code fragment for one very simple method.
  5219. MPW Pascal Listing 9
  5220.       ...
  5221.       (* Allocate the pixel image; use long multiplication to avoid overflow *)
  5222.       offBaseAddr := NewHandle(LongInt(bytesPerRow) * (bounds^.bottom -
  5223.             bounds^.top));
  5224.       IF offBaseAddr <> NIL THEN
  5225.          BEGIN
  5226.             (* Initialize fields common to indexed and direct PixMaps *)
  5227.             aPixMap^^.baseAddr := Ptr(offBaseAddr); (* Reference the image *)
  5228.       ...
  5229. PROCEDURE LockOffScreen(
  5230.    offScreenPort: CGrafPtr {Ptr to off-screen CGrafPort}
  5231.    );
  5232.    VAR
  5233.       offImageHnd: Handle; {Handle to the off-screen pixel image}
  5234. BEGIN
  5235.    (* Get the saved handle to the off-screen pixel image *)
  5236.    offImageHnd := Handle(offScreenPort^.portPixMap^^.baseAddr);
  5237.    (* Lock the handle to the pixel image *)
  5238.    HLock(offImageHnd);
  5239.    (* Put pixel image master pointer into baseAddr so that QuickDraw can use it *)
  5240.    offScreenPort^.portPixMap^^.baseAddr := offImageHnd^;
  5241. END;
  5242. PROCEDURE UnlockOffScreen(
  5243.    offScreenPort: CGrafPtr {Ptr to off-screen port}
  5244.    );
  5245.    VAR
  5246.       offImagePtr: Ptr;    {Pointer to the off-screen pixel image}
  5247.       offImageHnd: Handle; {Handle to the off-screen pixel image}
  5248. BEGIN
  5249.    (* Get the handle to the off-screen pixel image *)
  5250.    offImagePtr := offScreenPort^.portPixMap^^.baseAddr;
  5251.    offImageHnd := RecoverHandle(offImagePtr);
  5252.    (* Unlock the handle *)
  5253.    HUnlock(offImageHnd);
  5254.    (* Save the handle back in the baseAddr field *)
  5255.    offScreenPort^.portPixMap^^.baseAddr := Ptr(offImageHnd);
  5256. END;
  5257. MPW C Listing 9
  5258.         ...
  5259.         /* Allocate the pixel image; use long multiplication to avoid overflow */
  5260.         offBaseAddr = NewHandle( (unsigned long)bytesPerRow * (bounds->bottom -
  5261.                 bounds->top) );
  5262.         if (offBaseAddr != nil)
  5263.         {
  5264.             /* Initialize fields common to indexed and direct PixMaps */
  5265.             (**aPixMap).baseAddr = (Ptr)offBaseAddr; /* Reference the image */
  5266.         ...
  5267. void LockOffScreen(
  5268.     CGrafPtr offScreenPort) /* Pointer to the off-screen CGrafPort */
  5269. {
  5270.     Handle offImageHnd; /* Handle to the off-screen pixel image */
  5271.     /* Get the saved handle to the off-screen pixel image */
  5272.     offImageHnd = (Handle)(**offScreenPort->portPixMap).baseAddr;
  5273.     /* Lock the handle to the pixel image */
  5274.     HLock( offImageHnd );
  5275.     /* Put pixel image master pointer into baseAddr so that QuickDraw can use it */
  5276.     (**offScreenPort->portPixMap).baseAddr = *offImageHnd;
  5277. }
  5278. void UnlockOffScreen(
  5279.     CGrafPtr offScreenPort) /* Pointer to the off-screen CGrafPort */
  5280. {
  5281.     Ptr    offImagePtr; /* Pointer to the off-screen pixel image */
  5282.     Handle offImageHnd; /* Handle to the off-screen pixel image */
  5283.     /* Get the handle to the off-screen pixel image */
  5284.     offImagePtr = (**offScreenPort->portPixMap).baseAddr;
  5285.     offImageHnd = RecoverHandle( offImagePtr );
  5286.     /* Unlock the handle */
  5287.     HUnlock( offImageHnd );
  5288.     /* Save the handle back in the baseAddr field */
  5289.     (**offScreenPort->portPixMap).baseAddr = (Ptr)offImageHnd;
  5290. }
  5291. Listing 9 starts with a code fragment from the SetUpPixMap routine that’s modified so that it allocates a new handle for the off-screen pixel image instead of a new pointer. This handle is saved in the baseAddr field for now. When you’re about to draw into the off-screen graphics environment or to copy from it, the LockOffScreen routine in Listing 9 should be called with a pointer to the off-screen graphics environment’s CGrafPort as the parameter. It takes the handle to the pixel image from the baseAddr field of the off-screen graphics environment’s PixMap and passes it to _HLock which makes sure the pixel image can’t move in the heap. Then, the pixel image’s handle is dereferenced to get the master pointer to the pixel image, and this master pointer is copied into the baseAddr field. Now, QuickDraw can draw into or copy from the off-screen graphics environment.
  5292. When you’re finished drawing into the off-screen graphics environment, the pixel image should be unlocked, and the UnlockOffScreen routine in Listing 9 does this. The baseAddr field of the PixMap holds the pixel image’s master pointer, so this is passed to _RecoverHandle to get the pixel image’s handle. This handle is passed to _HUnlock to let the pixel image float in the heap again, and then this handle is saved in the baseAddr field.
  5293. One potentially useful addition to the LockOffScreen routine would be a call to _MoveHHi just before the call to _HLock. This helps reduce heap fragmentation while the pixel image is locked by moving it up as high in the heap as possible before locking it, allowing the other relocatable blocks to move without tripping over it. You have to be careful with _MoveHHi though because it not only moves the handle as high in the heap as possible, it moves other relocatable blocks out of the top of the heap to make room for the handle. This could involve moving huge amounts of memory, and it’s not unusual for _MoveHHi to take several seconds to do this.
  5294. How do you make an off-screen graphics environment that uses temporary memory for the pixel image? Temporary memory is allocated as handles, so there’s almost no difference between using temporary memory and using relocatable blocks in your own heap in the way that Listing 9 shows. All you have to do is replace the calls to _NewHandle, _HLock, and _HUnlock with calls to _TempNewHandle, _TempHLock, and _TempHUnlock. If temporary memory handles are real, then you don’t even have to replace the _HLock and _HUnlock calls—they work properly with temporary memory handles that are real.You can tell whether temporary memory handles are real or not by calling _Gestalt with the gestaltOSAttr selector. If the gestaltRealTempMemory bit is set, then all temporary memory handles are real. See the sections “About Temporary Memory” and “Using Temporary Memory” of Inside Macintosh Volume VI, pages 28-33 through 28-40.
  5295. How do you make an off-screen graphics environment that stores the pixel image on a NuBus memory card? The Macintosh Memory Manager doesn’t keep track of heaps on NuBus memory cards so it can’t be used to allocate memory on those cards, but if applications can use that card’s memory at will, then an application can set up the off-screen graphics environment with its pixel image in the NuBus card’s memory simply by setting the address of the card’s memory in the baseAddr field of the off-screen graphics environment’s PixMap instead of allocating anything.
  5296. If your NuBus memory card doesn’t require 32-bit addressing mode to access its memory, then setting the baseAddr to the address of the NuBus card’s memory is all you have to do. Some NuBus memory cards require its memory to be accessed in 32-bit addressing mode. Without 32-Bit QuickDraw, these memory cards can’t be used for storing the pixel image of an off-screen graphics environment because Color QuickDraw without 32-Bit QuickDraw always reads and writes pixel images in 24-bit addressing mode regardless of whether the pixel image is in main memory, on a NuBus video card, or on a NuBus memory card. With 32-Bit QuickDraw, Color QuickDraw automatically switches to 32-bit addressing mode before reading or writing a pixel image that’s on a video card. It won’t know to switch to 32-bit addressing mode if your off-screen graphics environment uses a pixel image on a NuBus memory card that’s not a video card, but you can tell it to make this switch by setting bit 2 of the pmVersion field of the PixMap for the off-screen graphics environment. This is normally done by logically ORing the pmVersion field with the predefined constant baseAddr32. See “About 32-Bit Addressing” in Issue 6 of develop, page 36, for more details about how QuickDraw handles addressing modes.
  5297. The GWorld Factor
  5298. In May 1989, 32-Bit QuickDraw was introduced as an extension to the system. While it had a lot of new features, the GWorld mechanism was the one that made the big news. GWorlds are off-screen graphics environments that you can have the system put together in one call. There’s no need for routines like CreateOffScreen, SetUpPixMap, or CreateGDevice—all of the off-screen graphics environment is set up with _NewGWorld. You can change most of its characteristics with _UpdateGWorld, set the current off-screen graphics environment with _SetGWorld, and get rid of the off-screen graphics environment with _DisposeGWorld. All the GWorld routines are described in the “Graphics Devices Manager” chapter of Inside Macintosh Volume VI. As an example, Listing 10 shows the same routine as the ExerciseOffScreen routine that’s shown in Listing 5, but Listing 10 uses GWorlds rather than the do-it-yourself routines that are defined in this Note.
  5299. MPW Pascal Listing 10
  5300. PROCEDURE ExerciseOffScreen;
  5301.    CONST
  5302.       kOffDepth  = 8;    {Number of bits per pixel in off-screen environment}
  5303.       rGrayClut  = 1600; {Resource ID of gray-scale clut}
  5304.       rColorClut = 1601; {Resource ID of full-color clut}
  5305.    VAR
  5306.       grayPort:    GWorldPtr;  {Graphics environment for gray off screen}
  5307.       colorPort:   GWorldPtr;  {Graphics environment for color off screen}
  5308.       savedPort:   GrafPtr;    {Pointer to the saved graphics environment}
  5309.       savedDevice: GDHandle;   {Handle to the saved color environment}
  5310.       offColors:   CTabHandle; {Colors for off-screen environments}
  5311.       offRect:     Rect;       {Rectangle of off-screen environments}
  5312.       circleRect:  Rect;       {Rectangles for circle-drawing}
  5313.       count:       Integer;    {Generic counter}
  5314.       aColor:      RGBColor;   {Color used for drawing off-screen}
  5315.       error:       OSErr;      {Error return from off-screen creation}
  5316. BEGIN
  5317.    (* Set up the rectangle for the off-screen graphics environments *)
  5318.    SetRect(offRect, 0, 0, 256, 256);
  5319.    (* Get the color table for the gray off-screen graphics environment *)
  5320.    offColors := GetCTable(rGrayClut);
  5321.    (* Create the gray off-screen graphics environment *)
  5322.    error := NewGWorld(grayPort, kOffDepth, offRect, offColors, NIL, []);
  5323.    IF error = noErr THEN
  5324.       BEGIN
  5325.          (* Get the color table for the color off-screen graphics environment *)
  5326.          offColors := GetCTable(rColorClut);
  5327.          (* Create the color off-screen graphics environment *)
  5328.          error := NewGWorld(colorPort, kOffDepth, offRect, offColors, NIL, []);
  5329.          IF error = noErr THEN
  5330.             BEGIN
  5331.                (* Save the current graphics environment *)
  5332.                GetGWorld(savedPort, savedDevice);
  5333.                (* Set the current graphics environment to the gray one *)
  5334.                SetGWorld(grayPort, NIL);
  5335.                (* Draw gray-scale ramp into the gray off-screen environment *)
  5336.                FOR count := 0 TO 255 DO
  5337.                   BEGIN
  5338.                      aColor.red := count * 257;
  5339.                      aColor.green := aColor.red;
  5340.                      aColor.blue := aColor.green;
  5341.                      RGBForeColor(aColor);
  5342.                      MoveTo(0, count);
  5343.                      LineTo(255, count);
  5344.                   END;
  5345.                (* Copy gray ramp into color off-screen colorized with green *)
  5346.                SetGWorld(colorPort, NIL);
  5347.                aColor.red := $0000; aColor.green := $FFFF; aColor.blue := $0000;
  5348.                RGBForeColor(aColor);
  5349.                CopyBits(GrafPtr(grayPort)^.portBits,
  5350.                      GrafPtr(colorPort)^.portBits,
  5351.                      grayPort^.portRect,
  5352.                      colorPort^.portRect,
  5353.                      srcCopy + ditherCopy, NIL);
  5354.                (* Draw red, green, and blue circles *)
  5355.                PenSize(8, 8);
  5356.                aColor.red := $FFFF; aColor.green := $0000; aColor.blue := $0000;
  5357.                RGBForeColor(aColor);
  5358.                circleRect := colorPort^.portRect;
  5359.                FrameOval(circleRect);
  5360.                aColor.red := $0000; aColor.green := $FFFF; aColor.blue := $0000;
  5361.                RGBForeColor(aColor);
  5362.                InsetRect(circleRect, 20, 20);
  5363.                FrameOval(circleRect);
  5364.                aColor.red := $0000; aColor.green := $0000; aColor.blue := $FFFF;
  5365.                RGBForeColor(aColor);
  5366.                InsetRect(circleRect, 20, 20);
  5367.                FrameOval(circleRect);
  5368.                (* Copy the color off-screen environment to the current port *)
  5369.                SetGWorld(savedPort, savedDevice);
  5370.                CopyBits(GrafPtr(colorPort)^.portBits,
  5371.                      savedPort^.portBits,
  5372.                      colorPort^.portRect,
  5373.                      savedPort^.portRect,
  5374.                      srcCopy, NIL);
  5375.                (* Dispose of the off-screen graphics environments *)
  5376.                DisposeGWorld grayPort);
  5377.                DisposeGWorld(colorPort);
  5378.             END;
  5379.       END;
  5380. END;
  5381. MPW C Listing 10
  5382. #define kOffDepth  8    /* Number of bits per pixel in off-screen environment */
  5383. #define rGrayClut  1600 /* Resource ID of gray-scale clut */
  5384. #define rColorClut 1601 /* Resource ID of full-color clut */
  5385. void ExerciseOffScreen()
  5386. {
  5387.     GWorldPtr  grayPort;    /* Graphics environment for gray off screen */
  5388.     GWorldPtr  colorPort;   /* Graphics environment for color off screen */
  5389.     CGrafPtr   savedPort;   /* Pointer to the saved graphics environment */
  5390.     GDHandle   savedDevice; /* Handle to the saved color environment */
  5391.     CTabHandle offColors;   /* Colors for off-screen environments */
  5392.     Rect       offRect;     /* Rectangle of off-screen environments */
  5393.     Rect       circleRect;  /* Rectangles for circle-drawing */
  5394.     short      count;       /* Generic counter */
  5395.     RGBColor   aColor;      /* Color used for drawing off-screen */
  5396.     OSErr      error;       /* Error return from off-screen creation */
  5397.     /* Set up the rectangle for the off-screen graphics environments */
  5398.     SetRect( &offRect, 0, 0, 256, 256 );
  5399.     /* Get the color table for the gray off-screen graphics environment */
  5400.     offColors = GetCTable( rGrayClut );
  5401.     /* Create the gray off-screen graphics environment */
  5402.     error = NewGWorld( &grayPort, kOffDepth, &offRect, offColors, nil, 0 );
  5403.     if (error == noErr)
  5404.     {
  5405.         /* Get the color table for the color off-screen graphics environment */
  5406.         offColors = GetCTable( rColorClut );
  5407.         /* Create the color off-screen graphics environment */
  5408.         error = NewGWorld( &colorPort, kOffDepth, &offRect, offColors, nil, 0 );
  5409.         if (error == noErr)
  5410.         {
  5411.             /* Save the current graphics environment */
  5412.             GetGWorld( &savedPort, &savedDevice );
  5413.             /* Set the current graphics environment to the gray one */
  5414.             SetGWorld( grayPort, nil );
  5415.             /* Draw gray-scale ramp into the gray off-screen environment */
  5416.             for (count = 0; count < 256; count++)
  5417.             {
  5418.                 aColor.red = aColor.green = aColor.blue = count * 257;
  5419.                 RGBForeColor( &aColor );
  5420.                 MoveTo( 0, count );
  5421.                 LineTo( 255, count );
  5422.             }
  5423.             /* Copy gray ramp into color off-screen colorized with green */
  5424.             SetGWorld( colorPort, nil );
  5425.             aColor.red = 0x0000; aColor.green = 0xFFFF; aColor.blue = 0x0000;
  5426.             RGBForeColor( &aColor );
  5427.             CopyBits( &((GrafPtr)grayPort)->portBits,
  5428.                     &((GrafPtr)colorPort)->portBits,
  5429.                     &grayPort->portRect,
  5430.                     &colorPort->portRect,
  5431.                     srcCopy | ditherCopy, nil );
  5432.             /* Draw red, green, and blue circles */
  5433.             PenSize( 8, 8 );
  5434.             aColor.red = 0xFFFF; aColor.green = 0x0000; aColor.blue = 0x0000;
  5435.             RGBForeColor( &aColor );
  5436.             circleRect = colorPort->portRect;
  5437.             FrameOval( &circleRect );
  5438.             aColor.red = 0x0000; aColor.green = 0xFFFF; aColor.blue = 0x0000;
  5439.             RGBForeColor( &aColor );
  5440.             InsetRect( &circleRect, 20, 20 );
  5441.             FrameOval( &circleRect );
  5442.             aColor.red = 0x0000; aColor.green = 0x0000; aColor.blue = 0xFFFF;
  5443.             RGBForeColor( &aColor );
  5444.             InsetRect( &circleRect, 20, 20 );
  5445.             FrameOval( &circleRect );
  5446.             /* Copy the color off-screen environment to the current port */
  5447.             SetGWorld( savedPort, savedDevice );
  5448.             CopyBits( &((GrafPtr)colorPort)->portBits,
  5449.                     &((GrafPtr)savedPort)->portBits,
  5450.                     &colorPort->portRect,
  5451.                     &savedPort->portRect,
  5452.                     srcCopy, nil );
  5453.             /* Dispose of the off-screen graphics environments */
  5454.             DisposeGWorld( grayPort );
  5455.             DisposeGWorld( colorPort );
  5456.         }
  5457.     }
  5458. }
  5459. _NewGWorld creates an off-screen graphics environment by creating a CGrafPort, PixMap, and GDevice—the same structures that you normally put together when you make an off-screen graphics environment yourself. In this aspect, and in fact in most aspects, there’s nothing magical about GWorlds. Do GWorlds make the CreateOffScreen, DisposeOffScreen, and their dependents useless? That depends on what your needs are. What follows are a few issues about off-screen drawing and how that determines whether you use your own routines, such as CreateOffScreen, to create and maintain off-screen graphics environments or whether you use GWorlds for the same purpose.
  5460. I Want the Best Performance!
  5461. As mentioned in the last paragraph, there’s nothing magical about GWorlds in most aspects. In one major aspect, there certainly is: the version of Color QuickDraw that runs with the 8•24 GC video card’s acceleration on knows about GWorlds and can cache their CGrafPort, PixMap, GDevice, inverse table, color table, and pixel image on the 8•24 GC card if there’s enough memory on it. When this is done, QuickDraw operations on the GWorld can be much faster than they’d normally be because the image data can stay in the card’s memory where the fast microprocessor is, and image data doesn’t have to move across NuBus in transfer operations between the GWorld and the screen. Additionally, these operations are executed asynchronously which increases the overall speed of your programs. For details about how the 8•24 GC card and GC QuickDraw work, see Guillermo Ortiz’s article, “Macintosh Display Card 8•24 GC: The Naked Truth,” in Issue 5 of develop.
  5462. 8•24 GC QuickDraw doesn’t know about the off-screen graphics environments that you create, so it doesn’t cache its structures. All QuickDraw commands that move image data between the off-screen graphics environment and the screen have to move the data across NuBus, and that slows down the operation in comparison to keeping all the image data on the card.
  5463. If you want the highest possible drawing and copying performance with the 8•24 GC card, you must use GWorlds for your off-screen graphics environments.
  5464. I Want to Use a NuBus Memory Card for My GWorld’s Off-Screen Pixel Image
  5465. One common desire is to use a NuBus memory card to hold a pixel image. Because GWorlds are so easy to set up, and because GWorlds have all the same parts that you can make for an off-screen graphics environment, it’s tempting to make a GWorld and then point the baseAddr of the GWorld’s PixMap at the NuBus card’s memory. But GWorlds are designed to be fairly atomic structures, so they can’t be changed in this way. You can change a GWorld’s dimensions, depth, and color table because there’s a routine (_UpdateGWorld) that is designed to change these things, but you can’t change the pixel image without risking future compatibility.
  5466. If you want to have an off-screen graphics environment use a NuBus video card to store the pixel image, you should set up your own off-screen graphics environment rather than use GWorlds. This is covered earlier in this Note in “Choosing Your Off-Screen Memory.”
  5467. I Want My Program to Work on All System Software Releases
  5468. GWorlds have been around since 32-Bit QuickDraw was released (while system software version 6.0.3 was current). Until system software version 7.0, 32-Bit QuickDraw was an optional part of the system, so you aren’t guaranteed use of GWorlds even under recent system software releases. Obviously, if GWorlds aren’t available and your program still has to work with off-screen graphics environments, then there’s no choice but to use your own routines for creating, maintaining, and disposing of off-screen graphics environments. What’s usually done in these cases is to check via _Gestalt whether GWorlds are available or not. If they aren’t, then you create your off-screen graphics environment with your own routines. If they are, then you can use GWorlds without having to take up memory with your code for creating off-screen graphics environments yourself.
  5469. Are We There Yet?
  5470. Reliable, understandable, and maintainable off-screen drawing routines means not taking short-cuts. The most common problems that people run into with off-screen drawing routines is the appearance of strange colors and the gradual degradation of reliability as the program does more off-screen drawing. Building an off-screen graphics environment out of a CGrafPort, GDevice, and PixMap or by using GWorlds, combined with an understanding of how Color QuickDraw uses off-screen graphics environments, helps get rid of these problems. Hopefully, this Note helps you understand these things so that you can get better programs out the door faster.
  5471. Further Reference:
  5472. •    Apple Computer, Inc., Inside Macintosh Volume I, Addison-Wesley, Reading, MA, 1985
  5473. •    Apple Computer, Inc., Inside Macintosh Volume V, Addison-Wesley, Reading, MA, 1988.
  5474. •    Apple Computer, Inc., Inside Macintosh Volume VI, Addison-Wesley, Reading, MA, 1991.
  5475. •    Knaster, S., Macintosh Programming Secrets, Addison-Wesley, Reading, MA, 1988.
  5476. •    Leak, B., “Realistic Color For Real-World Applications,” develop, January 1990, 4-21.
  5477. •    Ortiz, G., “Braving Offscreen GWorlds,” develop, January 1990, 28-40.
  5478. •    Ortiz, G., “Deaccelerated _CopyBits & 8•24 GC QuickDraw,” Macintosh Technical Note #289, January 1991.
  5479. •    Ortiz, G., “Macintosh Display Card 8•24 GC: The Naked Truth,”  develop, July 1990, 332-347.
  5480. •    Othmer, K., “QuickDraw’s CopyBits Procedure: Better Than Ever in System 7.0,” develop, Spring 1991, 23-42.
  5481. •    Tanaka, F., “Of Time and Space and _CopyBits,” Macintosh Technical Note #277, June 1990.
  5482. •    Zap, J., F. Tanaka, J. Friedlander, and G. Jernigan, “Drawing Into an Off-Screen Bitmap,” Macintosh Technical Note #41, June 1990.
  5483. NuBus is a trademark of Texas Instruments.
  5484. Of Time and Space and _CopyBits
  5485. Imaging    M.IM.TimeSpaceCopyBits
  5486. Written by:    Forrest Tanaka    June 1990
  5487. This Technical Note describes the various factors that can influence the speed of _CopyBits so that developers can set up conditions to achieve the best performance for the particular situation.
  5488. Can You Influence the Speed of _CopyBits?
  5489. _CopyBits has never been an “easy” QuickDraw routine, like _LineTo or even _OpenPort.  Most programmers who are just beginning to adjust themselves to the Macintosh usually have to give _CopyBits a few tries before the right bits copy to the right places.  Even many who feel that they have become Macintosh programmers still see reflections in their monitors of furrows between their eyebrows as they begin to press the key labelled “C.”
  5490. _CopyBits is one of those routines that is so full of subtlety, it has the beginnings of something that could be considered to be personality.  One subtlety involves the second most important thought that’s on the minds of any computer programmer:  execution speed.  Why is _CopyBits fast?  Why is it slow?  Can I influence its speed?  Is there really a clandestine state of reason?  Is there a price to speed?
  5491. Influences on the Speed of _CopyBits
  5492. Yes, you can influence the speed of _CopyBits.  Yes, it’s even predictable.  And yes, it’s possible that you have to compromise to get the maximum speed.  This Note is intended to give you a deeper understanding of the ways that the speed of _CopyBits can be affected; and hopefully you can then set up conditions for a _CopyBits call without the disturbing notion that someone else might be doing the same thing just a little bit better than you.
  5493. This Note talks about every factor that affects the speed of _CopyBits that I can think of and that can be reasonably controlled by a programmer or the person using an application.  There are other factors not mentioned in this Note because I felt that they were just too esoteric to describe with any meaning.
  5494. In each case, this Note tries to give real-life examples showing the effect of each factor.  These examples are just to give you a relative idea of the importance of each effect.  In real life, the effects of the different factors give results that could be a lot different from the results presented in this Note.  Each example is based on 100 _CopyBits calls from an off-screen pixel map to the screen on a Macintosh IIcx with an Apple Extended Video Card which is running System Software 6.0.5 and 32-Bit QuickDraw 1.2.  The off-screen pixel map is eight bits deep with the standard eight-bit color table and 256 pixels high by 256 pixels wide.  The screen is also in eight-bit color mode.  Calling _CopyBits to copy the entire off-screen pixel map to the screen 100 times takes 204 ticks, and this Note refers to this figure as the “standard test.”  Since a tick on a Macintosh is approximately 1/60 of a second, the standard test runs at slightly less than 30 frames per second.  As this Note discusses each factor, it presents an example with that factor changing and all other factors remaining the same as the standard test, which allows you to compare performance of the changed factor to that of the standard test of 204 ticks.
  5495. What follows is a discussion of each factor that can influence the speed of _CopyBits, in no particular order.
  5496. Dimensions of the Copied Area
  5497. One of  the most obvious factors has to do with the dimensions of the copied area.  _CopyBits takes as parameters two rectangles which specify the portion of the source pixel map from which you want to copy and the portion of the destination pixel map to which you want to copy it.  All other factors being equal, the larger the rectangles, the more pixels _CopyBits has to copy and the longer it takes to do the job.  To keep _CopyBits as fast as possible, copy the smallest rectangle possible.
  5498. Modifying the standard test so that _CopyBits only copies a 128-pixel wide by 128-pixel tall area produces a result of 109 ticks, which compares to the 204 tick performance for a 256-pixel wide by 256-pixel tall area.
  5499. QuickDraw is usually faster drawing wide things than it is drawing tall things, because consecutive pixels in memory are displayed horizontally.  Drawing a series of pixels that are next to each other horizontally is easy because QuickDraw simply has to set consecutive memory locations, while drawing a series of pixels that are next to each other vertically is just a little bit harder because the address of each pixel must be calculated.  _CopyBits is no exception to this general rule; it copies a row of pixels, goes to the next row, copies that row, goes to the next row, and so on.  The time spent going between rows is a lot more than the time going between pixels on one row, so the effect is that _CopyBits is faster copying a short and wide section of a pixel map than it is copying a tall and narrow one.  To keep _CopyBits as fast as possible, copy the shortest rectangle possible.
  5500. Modifying the standard test again so that the source and destination rectangles are 256 pixels wide by 50 pixels tall produces a result of 110 ticks, while modifying it so that the source and destination rectangles are 50 pixels wide by 256 pixels tall results in a time of 123 ticks.  These 13 ticks may not seem like a big deal, but combined with other factors, there may be a case where they make a big difference.
  5501. Shape and Size of the Clip, Visible, and Mask Regions
  5502. _CopyBits always makes sure that it stays within the lines, so to speak.  _CopyBits copies pixels clipped to the maskRgn that you pass as the last parameter to the call.  If the destination is the current GrafPort, _CopyBits additionally clips to a region that’s the intersection of the clipRgn and visRgn of the port.  If the intersection of these three regions is not rectangular, then _CopyBits has to check each pixel to make sure it falls within the intersection, and this check slows _CopyBits down.  If the intersection of these three regions is rectangular, then _CopyBits takes the fast case of copying constant-sized rows.  To keep _CopyBits as fast as possible, make sure the intersection of the clipRgn and visRgn of the destination GrafPort and the maskRgn is rectangular.  Of course, if the destination GrafPort is a window, then the visRgn is under the user’s control.
  5503. In general, if the region that you are copying into has straight vertical edges for the most part, the time penalty of using a non-rectangular region is not that bad.  Regions that only have small portions that are straight and vertical are the ones that slow _CopyBits down in a big way.  Regions that are twisted or that have holes or islands can also have a big effect upon the speed, depending upon how complicated they are.  As a rule of thumb, if a region looks like it slows _CopyBits, it probably does.
  5504. Modifying the standard test so the maskRgn is set to a circle that inscribes the example pixel map results in a time of 303 ticks, which is considerably longer than the standard test result of 204 ticks that involved copying a much larger area.  Modifying the maskRgn to a square with 226 pixels per side, which has about the same total area of the circle just used, results in a time of 176 ticks.
  5505. Transfer Modes
  5506. Macintoshes without Color QuickDraw have eight transfer modes that work with _CopyBits, while those Macintoshes with Color QuickDraw get an additional nine modes.  Because the algorithms for each of these modes can be pretty different from the others, the time it takes _CopyBits to work with each of these modes can vary radically.  For several of these modes, the speed of _CopyBits can vary a lot depending upon the particular image being copied and the image over which this image is copied.  It can also vary non-linearly depending upon the depth of the pixel maps.  The arithmetic modes in particular are highly optimized for 32-bit deep pixel maps.
  5507. The standard test copies a fairly average-looking ray-traced image to a white background.  Modifying the standard test to erase the background between each of the 100 calls to _CopyBits produced the following results for the modes listed (the tests were obviously also changed to reflect the proper mode.  In addition, to make the results a little more meaningful, the time it took to erase the background has been subtracted from each result.
  5508. srcCopy    204    notSrcCopy    469    addOver    1500    adMax    1504
  5509. srcOr        436    notSrcOr    444    addPin    1514    adMin    1501
  5510. srcBic    441    notSrcBic    441    subOver    1493    blend    1553
  5511. srcXor    438    notSrcXor    436    subPin    1525    transparent    1107
  5512.                         hilite    3127
  5513. Of course, the amount of time taken by some of these modes can be changed by changing the image to copy and the image over which it is copied.  These figures are just to give an idea of how fast or slow some of these modes are in this particular situation.
  5514. There is actually one more mode which is not mentioned:  ditherCopy.  Apple introduced this mode with 32-Bit QuickDraw, and it makes _CopyBits do error-diffusion dithering when copying a pixel map from one depth to a pixel map of a lesser depth or to a pixel map of the same depth with a different color table.  The speed of this transfer mode can be very fast or very slow, depending upon what pixel depths and colors are used and the particular image being copied.  The ditherCopy mode is not included in the table since the range of figures is potentially very large; play with it and see for yourself.  For more information about this mode, refer to the Color QuickDraw chapter in Inside Macintosh, Volume VI and the 32-Bit QuickDraw Developers’ Notes from APDA.
  5515. Colorization
  5516. There is a variation of _CopyBits if the destination pixel map is the current port and the foreground color is not black or the background color is not white.  If this is the case, then the source image is colorized when it’s copied.  For details, see Technical Note #163, Adding Color with _CopyBits.  Because this colorization requires extra processing, _CopyBits slows down.  To keep _CopyBits as fast as possible, make sure the foreground color is black, the background color is white, and that the current GDevice pixel map’s color table has white in the first position and black in the last position.
  5517. Modifying the standard test so that the foreground color is pure red and the background color pure blue produces a result of 579 ticks.
  5518. Pixel Alignment
  5519. The alignment of pixels in the source pixel map relative to their alignment the destination pixel map can be surprisingly important to the speed of _CopyBits, but what is pixel alignment?  Following is an example to demonstrate the concept of pixel alignment.  Imagine you want to perform a _CopyBits on a one-bit-per-pixel off-screen pixel map into a window on a one-bit-per-pixel screen, and the window is three pixels from the left edge of the screen.
  5520. If you copy the entire off-screen pixel map to the left edge of the window, then _CopyBits must realign the pixels.  Since the leftmost pixels of the off-screen pixel map are on a byte boundary, but the left edge of the window is three pixels away from a byte boundary, _CopyBits has to shift (or realign) each byte from the off-screen pixel map by three pixels before placing it on the screen.  The process of aligning the pixels slows down _CopyBits.
  5521. Figure 1 shows an example of this realignment.  An off-screen bit map specified by a pointer to a BitMap called offScreen is being copied to a window specified by a WindowPtr called window.  window, which is 256 pixels wide and 256 pixels high, is positioned 50 pixels from the top of the screen and three pixels from the left edge of the screen.  The screen has 512 pixels horizontally and 342 pixels vertically.  The source rectangle that is passed to _CopyBits is sourceRect and the destination rectangle is destinationRect.  Because offScreen is misaligned by three pixels, _CopyBits has to shift offScreen by three pixels before placing the image on the screen.
  5522. Figure 1–offscreen Needs Realignment
  5523. By adjusting the off-screen pixel map so that its leftmost pixels are also three pixels away from a byte boundary, _CopyBits can just copy the bytes without shifting, which is a lot faster.  This example holds true on all Macintosh models, whether they have Color QuickDraw or not.  To keep _CopyBits as fast as possible, make sure the pixels in memory are aligned with the pixels on the screen.  Figure 2 shows the same situation as Figure 1, except that offScreen is now properly aligned to window.
  5524. Figure 2–offscreen Aligned
  5525. Many, if not most, Color QuickDraw Macintoshes have video cards that can display one pixel per byte, so one would think that pixel alignment does not apply in these cases, since all pixels are at byte boundaries.  This statement is true enough, but there is still another kind of alignment that should be done on these machines.  Macintoshes with Color QuickDraw generally have full 32-bit microprocessors, and these microprocessors are at their fastest when they can transfer long words aligned on long-word boundaries in memory.
  5526. Modifying the last example so that the off-screen pixel map and the screen are both eight-bits-per-pixel, the pixel at the extreme top left corner of the off-screen pixel map is located at a long-word boundary, because the Macintosh Memory Manager forces it to be located there; however, the pixel at the extreme top left corner of the window is located three bytes away from the previous long-word boundary.  No bit shifting is needed, because each pixel takes up a whole byte, but _CopyBits does have to take the non-optimum case of copying long words on non-long-word boundaries.  This case works fine, but it is not quite as fast as it could be.  To keep _CopyBits as fast as possible, make sure pixels in the source and destination pixel maps are aligned on long-word boundaries.
  5527. Since 1984, Macintosh programmers have been told that rowBytes must be even.  That is still true, but to allow _CopyBits to copy an entire pixel map on long-word boundaries, rowBytes must be a multiple of four so that every line in a pixel map begins on a long-word boundary.  The following formula can be used to find the minimum rowBytes needed for a pixel map’s bounds rectangle with right and left coordinates of bounds.right and bounds.left, and a pixel depth of pixelDepth:
  5528. rowBytes := ((pixelDepth * (bounds.right - bounds.left) + 31) DIV 32) * 4;
  5529. Off-screen GWorld support, which was introduced with 32-Bit QuickDraw, can automatically set up a pixel map so that it’s properly aligned to any part of the destination pixel map or bit map.  You can specify that you want this by passing zero for the pixel depth and passing the rectangle of the destination area in global coordinates.  See the 32-Bit QuickDraw Developers’ Notes and “Braving Offscreen Worlds” in d e v e l o p, January 1990 for details.
  5530. The way that _NewGWorld aligns a GWorld is to set up the off-screen pixel map so that its rowBytes is four bytes wider than one would normally calculate.  Four bytes is the maximum amount that any pixel map would have to be realigned at any pixel depth.  The bounds rectangle’s left coordinate is set to the negative of the left coordinate of the destination rectangle in global coordinates modulo (32 / pixel depth), because this is maximum amount that a pixel map must be shifted to achieve perfect alignment.  To build on the earlier example, assume you have a 128-pixel wide, eight-bit deep, off-screen pixel map to copy to a window that is three pixels away from the left edge of an eight-bit color screen.
  5531. First, the rowBytes for the off-screen pixel map is set to 131 to allow room for realignment.  To align the off-screen pixel map to the on-screen window, the left coordinate of the off-screen bit map’s bounds is set to -3 and the right coordinate is still at 128.  Notice that the off-screen pixel map’s bounds is now 131 pixels wide.  Now, the pixels in the off-screen pixel map with a horizontal coordinate of 0 are located three bytes away from the previous long-word boundary.  The pixels on the left edge of the window are also located three bytes away from the previous long-word boundary, so _CopyBits can copy long words on long-word boundaries.
  5532. If a user moves the window so that it’s two pixels from the left edge of the screen, the off-screen pixel map must be realigned.  _UpdateGWorld is used to do this.  It changes the left coordinate of the off-screen pixel map’s bounds rectangle to -2 and then it shifts all the pixels in the off-screen pixel map one pixel to the left.  The extra four bytes in each row provide the room for this shifting.  (Gives you some new respect for the off-screen support, doesn’t it?)
  5533. This same discussion applies to any pixel depth, though shallower pixel depths require bit shifting rather than byte shifting.  The same principles apply, though.  Notice that in a 32-bit deep pixel map, all pixels are aligned on long-word boundaries, so no bit shifting or byte shifting ever needs to be done on one of those.  _NewGWorld still adds four to rowBytes even in this case, however.
  5534. Modifying the standard test so that the source and destination pixel maps are four bits deep with perfect pixel alignment produces a result of 78 ticks; however, if the destination pixel map is one pixel left of perfect alignment, the result is 228 ticks.
  5535. Speed of the Hardware, Of Course
  5536. Obviously, the speed of the machine your application is running on affects the speed of _CopyBits.  To make _CopyBits as fast as possible, spend a lot of money.  However, there is more to the speed of _CopyBits than the speed of the Macintosh itself.  When the Macintosh 128K was released, there was only one place for pixel images: main memory.  Today, the situation is more complicated.  If you have a modular Macintosh, the pixel image for the screen is in the memory of a NuBus™ video card.  If you have a Macintosh IIci, you can optionally abandon the NuBus video card and use on-board video which takes up part of main memory.  If you have an 8•24 GC card with enough memory, the pixel images can be cached in the card’s memory along with the screen’s pixel image.
  5537. All of these different locations have different access speeds, and that can affect the speed of _CopyBits.  Additionally, different Macintoshes have different RAM access speeds.  The Macintosh II, IIx, IIcx, and SE/30 have faster RAM than the Macintosh Plus or SE.  The Macintosh IIci RAM access speed is faster still, and the Macintosh IIfx has faster RAM access than the IIci.  Different video cards have different access speeds.  The IIci has a cache card option which can vastly speed up on-board video RAM access speed.  Third-party video cards that work in the Processor Direct Slot of the Macintosh SE and SE/30 have their own speed characteristics as well.
  5538. There can also be a speed cost for crossing the different areas.  If _CopyBits copies between main memory and a NuBus video card, the image data has to be transferred across NuBus.  NuBus is a speed bottleneck, so copying an image across NuBus is slower than copying the image from one part of the screen to another or copying from one part of main memory to another.  Modifying the standard test to create two windows and two off-screen pixel maps—all eight bits deep with the standard color table then doing every combination of copying between off-screens, between windows, and between off-screens and windows produces the following results:
  5539.                 Off-screen to off-screen:    147
  5540.                 Screen to screen:         188
  5541.                 Off-screen to screen:        204
  5542.                 Screen to off-screen:        201
  5543. Performing the standard test on a Macintosh IIfx running System Software 6.0.5 with an Apple Extended Video Card yields a result of 153 ticks, which is not too shabby considering that the transfer is still going through NuBus.
  5544. Depth of Pixel Maps
  5545. This factor is pretty obvious and is sort of similar to the effect of the dimensions of the copied area:  the more bits per pixel there are in the pixel map to copy, the more memory that _CopyBits has to move and the longer it takes to get the job done, assuming that the source and destination pixel maps have the same depth.  To make _CopyBits as fast as possible, make sure the pixel maps are as shallow as possible.
  5546. If _CopyBits has to copy to a pixel map that has a different depth from the source pixel map, the relationship between speed and depth becomes more complicated.  There is a tradeoff between the time taken to change the depth of an image and the absolute amount of data that has to be processed.  Copying from a 1-bit deep pixel map to a 32-bit deep pixel map is not that slow because the amount of image data in the 1-bit deep pixel map is so small.
  5547. Modifying the standard test to transfer a four-bit deep pixel map to another four-bit deep pixel map produces a result of 78 ticks.
  5548. Color Mapping
  5549. Color QuickDraw expects a color table attached to every indexed pixel map.  Color tables specify what color each pixel value in the pixel map represents.  When an application calls _CopyBits to copy a pixel map into another pixel map, _CopyBits reproduces the colors of the image in the source pixel map as closely as possible—even if the colors available in the destination pixel map are different than those available in the source pixel map.  This reproduction is done through a process called “color mapping.”
  5550. When color mapping is done, the source pixel values are transformed into RGBColor records using the source pixel map’s color table.  These RGBColor records are passed to _Color2Index which finds the pixel values of the closest available colors in the current GDevice pixel map’s color table.  This same process is done when the source and destination pixel maps have differing depths.  The color table attached to the destination pixel map is not used in color mapping.  The colors available in the current GDevice pixel map’s color table are used instead.  So, the destination pixel map must have the same colors for the same pixel values as the current GDevice.  Otherwise, the resulting image in the destination pixel map gets the wrong colors.  See Inside Macintosh, Volume V-141, The Color Manager, for a description of _Color2Index.  It’s also helpful to read the “Inverse Tables” section in the same chapter on page V-137.
  5551. Now, if the source color table contains virtually the same colors for the same pixel values as the current GDevice pixel map’s color table, then any particular pixel value has the same color regardless of whether it is in the source or destination pixel map.  In this case, color mapping is a waste of time, because the pixels can be copied directly from the source pixel map to the destination pixel map without a loss of color fidelity.  _CopyBits takes advantage of this special case to yield some big speed improvements.  How is this special case detected?  Before this question is answered, it’s useful to understand how Color QuickDraw uses color tables.
  5552. The ctSeed Field
  5553. The first field in a color table is the ctSeed field.  This LongInt can be thought of as the color table’s version of the scrapCount field of the desk scrap.  Whenever an application calls _ZeroScrap, the desk scrap’s scrapCount is changed.  An application can tell that the desk scrap has changed by checking to see if the scrapCount has changed.  Similarly, whenever the contents of a color table are changed in any way, the ctSeed field should be changed to indicate to anyone using that color table that it has been modified.
  5554. Additionally, Color QuickDraw often uses the ctSeed as a fast check for color table equality.  If two color tables have the same ctSeed, then Color QuickDraw often assumes that their contents are equivalent.
  5555. After creating a new color table, an application has to get a valid value for the ctSeed field, and it can do so with the _GetCTSeed routine.  This routine generates a valid ctSeed value suitable for a new color table.  See Inside Macintosh, Volume V-143, The Color Manager, for a description of _GetCTSeed.
  5556. System Software 7.0 and 32-Bit QuickDraw each offer a routine called _CTabChanged which should be called after a color table is modified.  It takes a handle to the changed color table as a parameter.  If the _CTabChanged routine is not available, then the application should instead change ctSeed to a different valid value by calling _GetCTSeed and assigning the result to ctSeed, just like it’s done when the application creates a new color table.  You must use either one of these methods to tell Color QuickDraw that the color table has changed, or else the modified color table could be confused with the old color table, or with some other color table—this is especially critical if an 8•24 GC card is being used.  See the 32-Bit QuickDraw Developers’ Notes for details about the _CTabChanged routine.
  5557. The ctFlags Field
  5558. The ctFlags field is used as a set of flags that indicate some characteristics of the color table.  Currently, only the top two bits of ctFlags are of any interest to developers.  The most significant bit of ctFlags (bit 15) indicates whether the color table is a sequential color table or an indexed color table.  Bit 14 indicates that the color table is a special kind of sequential table if it is set.  In these kinds of color tables, the value fields indicate a palette entry in the destination window’s palette.  See the Palette Manager section of the 32-Bit QuickDraw Developers’ Notes for a discussion about this capability.
  5559. Sequential Color Tables
  5560. If bit 15 of ctFlags is set, the color table is a sequential color table.  Sequential color tables are usually found attached to GDevice pixel maps and to GWorld pixel maps.
  5561. In sequential color tables, the position of each color in the color table indicates the pixel value to which it corresponds.  For example, the fifth entry in a sequential color table always has a pixel value of four (pixel values start at zero).  The value field of each ColorSpec is not defined in sequential color tables, though they are used in color tables for screen GDevice records to indicate that a particular color is reserved, protected, or both.
  5562. Indexed Color Tables
  5563. If bit 15 and 14 of ctFlags are clear, the color table is an indexed color table.  In indexed color tables, the value field of each ColorSpec indicates the pixel value of the RGB in that ColorSpec.  For example, if the fifth ColorSpec in the color table has a value field containing 10, then that color has a pixel value of 10, not 4, as it would have been if this were a sequential color table.
  5564. Color Mapping or Non-Color Mapping
  5565. As noted before, _CopyBits can detect whether it has to do color mapping or not, so that it can take advantage of the speed benefits of no color mapping if possible.  How is this done?  First, _CopyBits checks to see if the ctSeed field of the source and destination color tables are the same and if the source and destination pixel maps have the same depths.  If both of these conditions are true, then _CopyBits assumes that the two color tables are identical and it just copies the pixels directly without color mapping.  If the ctSeed fields are different, _CopyBits checks manually through all of the colors in the source pixel map’s color table map to see if they map to the same pixel values in the current GDevice pixel map’s color table as they do in their own color table.  If they do, then _CopyBits again takes the fast case.
  5566. So to keep _CopyBits as fast as possible, make sure that the source and destination color tables have virtually the same colors for the same pixel values.  This applies even if one color table is an indexed color table and the other is a sequential color table, or if the source and destination color tables are both indexed but the order of the ColorSpec records differ.
  5567. Modifying the standard test so that the source pixel map has a color table that is the reverse of the standard eight-bit system color table (the grays have low pixel values and the light pinks and yellows have high pixel values) and the destination pixel map has the standard eight-bit system color table produces a result of 470 ticks.
  5568. By the way, color tables do not make any sense for direct pixel maps, so this discussion does not apply to them.  Direct pixel maps do have a color table attached to them, but they’re just there so that an application that assumes that a color table is attached does not bomb.
  5569. Scaling
  5570. If the source and destination rectangles are the same size, _CopyBits has the fairly easy task of just transferring the pixels from the source pixel map to the destination pixel map; however, if the source and destination rectangles are different sizes, _CopyBits has to scale the copied image, which slows it down a lot.  To keep _CopyBits as fast as possible, make sure the source and destination rectangles have the exact same dimensions.
  5571. Modifying the standard test to copy a 128 by 128 pixel portion of the source pixel map to the whole 256 by 256 pixel window produces a result of 1,159 ticks.
  5572. Of Time and Space
  5573. Hopefully, this Note makes it a lot clearer to you how to set up a situation in which your _CopyBits calls are as fast as your situation allows.  It’s important to realize that this Note does not cover every single factor that has an influence on the speed of _CopyBits.  There are many more factors which are just too unpredictable.  For example, _CopyBits is highly optimized for many special cases, and those optimizations can have a big effect on the speed of the copy.  Also, the speed of _CopyBits can be affected by interrupt-level tasks.  It’s up to you to fine tune your programs to your particular situations.
  5574. Further Reference:
  5575. •    Inside Macintosh, Volume I, QuickDraw
  5576. •    Inside Macintosh, Volume V, The Color Manager
  5577. •    Inside Macintosh, Volume VI, Color QuickDraw
  5578. •    Technical Note M.IM.ColorCopyBits, Adding Color With _CopyBits
  5579. •    d e v e l o p, January 1990, “Realistic Color for Real-World Applications”
  5580. •    d e v e l o p, January 1990, “Braving Offscreen GWorlds”
  5581. •    32-Bit QuickDraw Developers’ Notes (APDA)
  5582. NuBus is a trademark of Texas Instruments
  5583. ‡◊#ˇ ˇˇˇˇ#◊°d WORDS †å°d WORDR…†Ç 
  5584. /ZÅ#
  5585.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  5586. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  5587. .WIQkWIQk+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  5588. Ä({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  5589. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  5590.     l+&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  5591. BÄ(Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É°dWORD†ç
  5592. IR.°dONLNd{<éë(®Z'32-Bit QuickDraw:  Version 1.2 Features
  5593. °dONLNd(ç<úr*Imaging°dONLNd0çöú˛(∏∏ M.IM.32BitQD
  5594. °dONLNd=®<¥q(–Z Written by:°dONLNdI®Ñ¥Œ)HGuillermo Ortiz°dONLNdY®À¥˛(–È
  5595. April 1990°dONLNdd¿<ÃÁ(ËZOThis Technical Note describes the changes and enhancements to 32-Bit QuickDraw °dONLNd≥¿ÁÃ˛(Ëfrom°dONLNd∏Ã<ÿb(ÙZversion °dONLNd¿Ãbÿ˛)&S1.0 (as shipped on the original Color Disk) to version 1.2, which ships with System°dONLNdÿ<‰R(Z9Software 6.0.5 and later.  This Note assumes familiarity °dONLNdMÿR‰l(pwith °dONLNdRÿl‰ø)Inside Macintosh°dONLNdbÿø‰˛)S , Volume V,°dONLNdn‰<E( Z4Color QuickDraw, and 32-Bit QuickDraw release notes. X
  5596. °dONLNd£<$∂*432-Bit QuickDraw
  5597. °dONLNd¥0<<®*GVersion 1.0 of 32-Bit QuickDraw shipped in May 1989 in response to the °dONLNd˚0®<˛(XΔgrowing need for°dONLNd <<HZ(dZColor °dONLNd<ZH˛)TQuickDraw support for direct color devices and pictures (PICT2) and video boards for°dONLNdgH<Ty(pZ
  5598. large-screen °dONLNdtHyT˛)=Mmonitors which require 32-bit addressing for black and white operation.  This°dONLNd¬T<`(|Z]original version of 32-Bit QuickDraw was a separate file that had to be copied manually into °dONLNdT`˛(|the°dONLNd#`<l(àZ-System Folder.  With the introduction of the °dONLNdP`l˛)‘/Macintosh IIci, Apple put 32-Bit QuickDraw into°dONLNdÄl<xÃ(îZPROM.  Now System Software 6.0.5 and later offer 32-Bit QuickDraw as an integral °dONLNd–lÃx˛(îÍ part of the°dONLNd‹x<ÑÉ(†ZASystem Software which can be installed by the standard Installer °dONLNdxÉÑ˛(†°(although the file is still°dONLNd9Ñ<êj(¨Z
  5599. separate).°dONLNdDú<®n*
  5600. This Note °dONLNdNún®˛)2Ndescribes the changes and enhancements in version 1.2 of 32-Bit QuickDraw from°dONLNdù®<¥Õ(–Zversion 1.0.  Beginning with °dONLNd∫®Õ¥˛)ë>version 1.2, QuickDraw functionality is identical on all Color°dONLNd˘¥<¿ˆ(‹Z&QuickDraw machines, including all the °dONLNd¥ˆ¿˛)∫3performance improvements which were originally only°dONLNdS¿<Ã∂(ËZavailable in the IIci ROM.
  5601. °dONLNdn‰<ÛB*'%New Features (In No Particular Order)
  5602. °dONLNdîˇ< *#PICTs Contain Font Name Information°dONLNd∏<$*&Every time you draw text inside of an ,
  5603. Courier°dONLNdfi#d)‘ _OpenPicture°dONLNdÍd$Ö)T and °dONLNdÔÖ#‡)!
  5604. _ClosePicture°dONLNd¸‡$˛)[ pair,°dONLNd$<0E(LZ7QuickDraw stores the name of the current font and uses °dONLNd:$E0˛(Lc&it when playing back the picture.  The°dONLNda0<<ë(XZIopcode used to save this information is $002C and its data is as follows:
  5605.     °dONLNd´H<Sπ*    PictFontInfo = Record°dONLNd≈R<]ü*
  5606. G                     length   : Integer;    { length of data in bytes }°dONLNd
  5607. \<gü*
  5608. G                     fontID   : Integer;    { ID in the source system }°dONLNdUf<qˇ*
  5609. '                     fontName : Str255;°dONLNd}p<{Ø*
  5610.                    END;
  5611. °dONLNdïÜ<íΔ*QuickDraw only saves this °dONLNdØÜΔí˛)ä;information one time for each font used in a picture.  When°dONLNdÎì<ü‚(ªZ#QuickDraw plays back a picture, it °dONLNdì‚ü
  5612. )¶    uses the °dONLNdí
  5613. û7)+fontID°dONLNdì7ü˛)*+ as a reference into the list of font names°dONLNdIü<´N(«Z<which are used to set the correct font on the target system. ◊X◊
  5614. *%'32-Bit QuickDraw:  Version 1.2 Features(Ï1) of 5ˇ°¿Ù%%DSIDICT:_cv
  5615. currentdict /bu known {bu}if
  5616. userdict /_cv known not{userdict /_cv 30 dict put}if
  5617. _cv begin
  5618. /bdf{bind def}bind def
  5619. currentscreen/cs exch def/ca exch def/cf exch def
  5620. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  5621. /ss{//cf //ca //cs setscreen}bdf
  5622. /stg{ss setgray}bdf
  5623. /strgb{ss setrgbcolor}bdf
  5624. /stcmyk{ss cvcmyk}bdf
  5625. /min1{dup 0 eq{pop 1}if}bdf
  5626. end
  5627. currentdict /bn known {bn}if
  5628. †ø ◊#ˇ ˇˇˇˇ#◊ 
  5629. IR,Times
  5630. .+6-Macintosh Technical Notes /4/˘
  5631. °dONLNd)5µ*$ For example, the following code:,
  5632. Courier
  5633.     °dONLNd!ALv*F    GetFNum('Venice', theFontID);    { Set a font before opening PICT}°dONLNdhKVê*
  5634.     TextFont(theFontID);°dONLNdÅ_j—*%    pHand2 := OpenPicture (pictRect);°dONLNdßitÜ*
  5635.         MoveTo(20,20);°dONLNdæs~‡*
  5636. (        DrawString(' Better be Venice');°dONLNdÁáí—*%        GetFNum('Geneva', theFontID);°dONLNd
  5637. ëú§*
  5638.         TextFont(theFontID);°dONLNd*õ¶Ü*
  5639.         MoveTo(20,40);°dONLNdA•∞©*
  5640.         DrawString('Geneva');°dONLNd_πƒ€*'        GetFNum('New York', theFontID);°dONLNdá√Œ§*
  5641.         TextFont(theFontID);°dONLNd§ÕÿÜ*
  5642.         MoveTo(20,60);°dONLNdª◊‚≥*
  5643.         DrawString('New York');°dONLNd€Îˆ—*%        GetFNum('Geneva', theFontID);°dONLNdı§*
  5644.         TextFont(theFontID);°dONLNdˇ
  5645. Ü*
  5646.         MoveTo(20,80);°dONLNd5    ©*
  5647.         DrawString('Geneva');°dONLNdSm*
  5648.     ClosePicture;
  5649. °dONLNdf)5*:generates a picture containing font information like this:
  5650.     °dONLNd°ALÅ*    OpCode 0x002C {9,°dONLNd∏KVä*
  5651. J        "0005 0656 656E 6963 65"}              /* save current font     */°dONLNdU`w*
  5652.     TxFont 'venice'°dONLNd_jÍ*
  5653. *    DHDVText {20, 20, " Better be Venice"}°dONLNdBitä*
  5654. J    OpCode 0x002C {9,                          /* save next font name   */°dONLNdçs~Ω*
  5655. !        "0003 0647 656E 6576 61"}°dONLNdØ}àw*
  5656.     TxFont 'geneva'°dONLNd√áíï*
  5657.     DVText {20, "Geneva"}°dONLNd›ëúä*
  5658. J    OpCode 0x002C {11,                         /* ditto                 */°dONLNd(õ¶÷*
  5659. &        "0002 084E 6577 2059 6F72 6B"}°dONLNdO•∞|*
  5660.     TxFont 'newYork'°dONLNddØ∫ü*
  5661.     DVText {20, "New York"}°dONLNdÄπƒÄ*
  5662. H    TxFont 'geneva'                            /* second Geneva does not°dONLNd…√Œä*
  5663. J                                                 need another $002C guy */°dONLNdÕÿï*
  5664.     DVText {20, "Geneva"}
  5665. °dONLNd.„Ô•*VThis feature works regardless of the type of picture being saved, including old style °dONLNdÑ„•Ô⁄( √
  5666. PICTs in a°dONLNdè¸¥(6black and white port.  Using °dONLNd¨Ô¥˚)ú
  5667. _OpenCPicture°dONLNdπ¸O)[  instead of °dONLNd≈ÔO˚£)@ _OpenPicture°dONLNd—£¸⁄)T  to start a°dONLNd›¸($64recording session results in the same functionality.°dONLNd ˛*&Direct PixPat Structures Now Supported°dONLNd9-9*3QuickDraw now supports 16-bit and 32-bit per pixel °dONLNdl,8=)˚PixPat°dONLNdr-=9u)*
  5668.  structures (°dONLNd,u8¬)8 patType = 1°dONLNdä-¬9–)M).  °dONLNdé-–9⁄)In°dONLNdë:F±(b6 addition, it now supports a new °dONLNd±9±E‚)ôpatType°dONLNd∏:‚Fˆ)1 (3) °dONLNdΩ:ˆF⁄).which uses dithering whenever 16-bit or 32-bit°dONLNdÌFR˘(n60pixel patterns are displayed on indexed devices.°dONLNd^j˙*%Direct 'cicn' Resources Now Supported°dONLNdDwÉ*3QuickDraw now supports 16-bit and 32-bit per pixel °dONLNdwvÇ=)˚'cicn'°dONLNd}w=É⁄)*! resources.  The 16-bit per pixel°dONLNdüÑêJ(¨6Dis particularly cool since you save the space required for an 8-bit °dONLNd„ÉJèt(¨h'clut'°dONLNdÈÑtêx)*.°dONLNdÎú®ô(ƒ6<GWorlds Can Now Be Allocated in MultiFinder Temporary Memory ◊4◊˘
  5669. *(2) of 5(ÏS'32-Bit QuickDraw:  Version 1.2 Featuresˇ◊#ˇ ˇˇˇˇ#◊ 
  5670. IR,Times
  5671. .+Z-Developer Support Center(-
  5672. April 1990 /X/
  5673. °dONLNd*<6S(RZYou °dONLNd*S6æ)can now use the new ,
  5674. Courier°dONLNd)æ5)k
  5675. useMFTempBit °dONLNd%*6s)\(bit 2) in a call to °dONLNd:)s5≤)Y    NewGWorld°dONLNdC*≤6˛)? as an option to°dONLNdT6<B/(^Z1allocate pixels in MultiFinder temporary memory. °dONLNdÖ6/B˛)Û) In addition, you can now allocate screen°dONLNdØB<N˛(jZ]buffers in MultiFinder temporary memory using the following routine, defined in Pascal and C:
  5676.     °dONLNd
  5677. Z<eã*CFUNCTION NewTempScreenBuffer (globalRect: Rect; purgeable: BOOLEAN;°dONLNdQd<o,*
  5678. 0                              VAR gdh: GDHandle;°dONLNdÇn<y©*
  5679. I                               VAR offscreenPixMap: PixMapHandle): QDErr;°dONLNdÃx<Éê*
  5680. D             INLINE $203C,$000E, $0015,$AB1D; { Move.L #$000E0015,D0°dONLNdÇ<çc*
  5681. ;                                               _QDOffscreen°dONLNdMå<ó"*
  5682. .                                             }°dONLNd|†<´ö*Fpascal QDErr NewTempScreenBuffer (Rect *globalRect, BOOLEAN purgeable,°dONLNd√™<µ*
  5683. ,                              GDHandle *gdh,°dONLNd¥<øh*
  5684. <                              PixMapHandle *offscreenPixMap)°dONLNd-æ<…*
  5685. ,             ={0x203C,0x000E,0x0015,0xAB1D};
  5686. °dONLNd[‘<‡‚*Indexed to Indexed Dithering°dONLNdxÏ<¯{*    _CopyBits°dONLNdÅÌ{˘ñ)? now °dONLNdÜÌñ˘’)
  5687. supports the °dONLNdìÏ’¯)?
  5688. ditherCopy°dONLNdùÌ˘˛)F. transfer mode whenever the destination device°dONLNdÃ˘<7(!Z7is between one and eight bits per pixel, regardless of °dONLNd˘7˛)˚)the depth of the source image.  With this°dONLNd-<ä(-ZFsupport, an eight-bit image can now be approximated on a one-bit or a °dONLNdsä˛(-®four-bit device by using°dONLNdå<Õ(9ZXerror diffusion.  Furthermore, an eight-bit image could also be dithered to a different °dONLNd‰Õ˛(9Î
  5689. set of 256°dONLNdÔ<)ù(EZNcolors or a four-bit image could be dithered to an eight-bit device that does °dONLNd=ù)˛(Eªnot have the desired°dONLNdR)<5](QZcolors.°dONLNdZA<M *"32-Bit Addressed PixMap Structures°dONLNd}Z<f§*Version 1.2 defines a °dONLNdìZ§fº)hnew °dONLNdóYºe˚)    pmVersion°dONLNd†Z˚f)? (°dONLNd¢Yeg)baseAddr32 = 4°dONLNd∞ZgfΔ)d) for 32-bit pointer °dONLNd≈YΔe˛)_baseAddr°dONLNdŒg<s(èZ
  5690. values.  The °dONLNd€fr∑)CbaseAddr°dONLNd„g∑sÊ)8     of such °dONLNdÏfÊr)/PixMap°dONLNdÚgs≥)*# structures is treated as a 32-bit °dONLNdg≥s˛)£address, so no°dONLNd$s<ú(õZJstripping or address translation is performed on it in 32-bit mode.  This °dONLNdnsú˛(õ∫is a specially useful°dONLNdÑÄ<åË(®Z#feature when the base address of a °dONLNdßËã)¨PixMap°dONLNd≠Äå)* °dONLNdÆÄår)points to a NuBus
  5691.     °dONLNdø~râz(•ê™
  5692. °dONLNd¿Äzå˛+ address, for example in a°dONLNd€å<òü(¥Zvideo grabber board.°dONLNd•<±x* A new call, °dONLNd¸§x∞≈)< Pixmap32Bit°dONLNd•≈±)M, is now available °dONLNd•±à)Zto inquire if a given °dONLNd0§à∞≤)iPixMap°dONLNd6•≤±˛)* requires 32-bit°dONLNdG±<Ωs(ŸZ addressing.
  5693.     °dONLNdS…<‘'*/FUNCTION Pixmap32Bit(pmh:pixMapHandle):Boolean;°dONLNdÉ”<fic*
  5694. ;    INLINE $203C,$0004, $0016,$AB1D; { Move.L #$00040016,D0°dONLNdø›<Ë6*
  5695. 2                                      _QDOffscreen°dONLNdÚÁ<Úı*
  5696. %                                    }°dONLNd˚<*,pascal BOOLEAN Pixmap32Bit(pixMapHandle pmh)°dONLNdE<ı*
  5697. %    = {0x203C,0x0004, 0x0016,0xAB1D};
  5698. °dONLNdl<'fl*Updated GetPixBaseAddress°dONLNdÜ4<@§*Version 1.2 updates °dONLNdö3§?)hGetPixBaseAddress°dONLNd´4@ã)w to return the address °dONLNd¬4ã@≤)pof any °dONLNd…3≤?‹)'PixMap°dONLNdœ4‹@˛)*.  The°dONLNd÷A<Mk(iZ@routine does the right address translation or stripping for all °dONLNd    @kLï(iâPixMap°dONLNd    AïMö)* °dONLNd    AöM˛)structures, including°dONLNd    3N<Zá(vZscreen devices, °dONLNd    CNáZR)K'unlocked GWorlds, and 32-bit addressed °dONLNd    jMRY|)ÀPixMap°dONLNd    pN|Z˛)* structures.  The address it°dONLNd    ç[<gk(ÉZ returns is °dONLNd    ò[kgs)/6only valid in 32-bit addressing mode. Also unless the °dONLNd    ŒZsfù(ÉëPixMap°dONLNd    ‘[ùg˛)* is locked and made°dONLNd    Ëh<tÛ(êZ%unpurgeable, the address returned by °dONLNd
  5699.  
  5700. gÛsj)∑GetPixBaseAddress°dONLNd
  5701. hjtz)w is °dONLNd
  5702. "hzt˛)only valid until any call to°dONLNd
  5703. ?t<Ä‚(úZ!QuickDraw or the toolbox is made.°dONLNd
  5704. aå<òÒ*_CopyBits from Screen Devices ◊X◊
  5705. *8'32-Bit QuickDraw:  Version 1.2 Features(Ï3) of 5ˇ,◊#ˇ ˇˇˇˇ#◊ 
  5706. IR,Times
  5707. .+6-Macintosh Technical Notes /4/˘
  5708. °dONLNd**4The picture recording mechanism has changed so that °dONLNd4*L)ˇ if you call ,
  5709. Courier°dONLNd@L)ã)5    _CopyBits°dONLNdIã*⁄)? while recording°dONLNdZ+7é(S6a picture with the source °dONLNdt*é6∏)vPixMap°dONLNdz+∏7‡)*     being a °dONLNdÉ+‡7⁄)(5screen device, the data is correctly accumulated into°dONLNdπ8D*(`6>the picture.  Note that if the screen being copied is not the °dONLNd˜8*Dï(`Hmain screen, then the °dONLNd
  5710. 7ïCø)kPixMap°dONLNd8øD⁄)* must°dONLNdEQ(m6be a 32-bit addressed °dONLNd/DP©)gPixMap°dONLNd5E©Q∞)*. °dONLNd7E∞Q⁄)@ No auxiliary screen buffer is allocated if the source rectangle°dONLNdxQ]à(y6covers only one screen.°dONLNdêiu∫*New Picture Recording Trap°dONLNd´Çéx*Version 1.2 adds a °dONLNdæÇxé™)`
  5711. new call, °dONLNd»Å™ç)2
  5712. _OpenCPicture°dONLNd’Çé⁄)[-, to create pictures that contain information°dONLNdéöÙ(∂60regarding the native resolution of the recorded °dONLNd3éÙö⁄)‹-image.  When QuickDraw draws this picture, it°dONLNdaö¶†(¬6Qscales the image to the resolution of the target device.  Applications that need °dONLNd≤ö†¶⁄(¬æ to scale the°dONLNdø¶≤˚(Œ61images directly can also access this information.
  5713.     °dONLNdÒæ…?*;FUNCTION OpenCPicture(VAR CPictInfo:CPictRecord):PicHandle;°dONLNd-»”m*
  5714.     INLINE $AA20;°dONLNd?‹Á!*5pascal PicHandle OpenCPicture(CPictRecord *CPictInfo)°dONLNduÊÒ^*
  5715.     =  0xAA20;
  5716. °dONLNdѸ5*where
  5717.     °dONLNdä|*struct CPictRecord {°dONLNdü)∑*
  5718. S      Rect CPicFrame;           /* Bounding rect of Picture at native resolution */°dONLNdÛ(3∑*
  5719. S      Fixed CPicHRes;           /* native horizontal resolution in pixels/inch   */°dONLNdG2=∑*
  5720. S      Fixed CPicVRes;           /* native vertical resolution in pixels/inch     */°dONLNdõ<G∑*
  5721. S      short CPicVersion;        /* version of this PICT info set to -2           */°dONLNdÔFQ∑*
  5722. S      short reserved;           /* for future expansion set to zero              */°dONLNdCP[∑*
  5723. S      long reserved;            /* for future expansion set to zero              */°dONLNdóZeJ*
  5724.  
  5725.         };
  5726. °dONLNd¢p|*5The new picture header data looks like the following:°dONLNdÿà`î©+H
  5727. Size in bytes°dONLNdÊà√î„)cName°dONLNdÎà/îp)l Description ≥|≥µ°dONLNd¯ñ¢Ö(æù2°dONLNd˙ï√°Ù)DpicSize°dONLNdñ¢ê)Zlow word of picture size°dONLNd£ØÖ(Àù8°dONLNd¢√Æ˚)DpicFrame°dONLNd'£Øã)Zbounding box at 72 dpi Œ|Œµ°dONLNd>»<‘ê(ZPicture Header ÛXÛ√°dONLNdM÷<‚B*2°dONLNdO’i·Ø)-
  5728. version op°dONLNdZ÷Â?)cversion opcode = $0011°dONLNdq„<ÔB( Z2°dONLNds‚iÓö)-version°dONLNd{„ÃÔC)cversion number = $02FF°dONLNdí<¸B(Z2°dONLNdîÔi˚®)-    Header op°dONLNdûø@)cheader opcode  = $0C00°dONLNdµ˝<    B(%Z2°dONLNd∑¸iö)-version°dONLNdø˝Ã    H)c-2 for PICTs created with °dONLNdŸ¸H£)|
  5729. _OpenCPicture°dONLNdÁ
  5730. <B(2Z2°dONLNdÈ    i°)-reserved°dONLNdÚ<#B(?Z4°dONLNdÙi"Ö)-HRes°dONLNd˘Ã#S)cnative horizontal resolution (°dONLNdS"v)áFixed°dONLNdv#z)#)°dONLNd$<0B(LZ4°dONLNd #i/Ö)-VRes°dONLNd%$Ã0F)cnative vertical resolution (°dONLNdA#F/i)zFixed°dONLNdF$i0m)#)°dONLNdH1<=B(YZ8°dONLNdJ0i<ö)-SrcRect°dONLNdR1Ã=7)cnative source rectangle°dONLNdj><JB(fZ4°dONLNdl=iI°)-reserved iXi√°dONLNdudpÓ(å6,The following is a sample PICT created with °dONLNd°cÓoI)÷
  5731. _OpenCPicture°dONLNdÆdIpL)[:
  5732.     °dONLNd∞|áv(£6F    00 48                          /* low word of size              */°dONLNd˜Üëv*
  5733. F    00 00 00 00 00 7D 00 7D        /* picFrame at 72 dpi            */°dONLNd>êõv*
  5734. F    00 11                          /* PICT version opcode           */°dONLNdÖö•v*
  5735. F    02 FF                          /* version number                */ ◊4◊˘
  5736. *+4) of 5(ÏS'32-Bit QuickDraw:  Version 1.2 Featuresˇ
  5737. ,◊#ˇ ˇˇˇˇ#◊ 
  5738. IR,Times
  5739. .+Z-Developer Support Center(-
  5740. April 1990 /X/,
  5741. Courier
  5742.     °dONLNd<(ö(DZF    0C 00                          /* PICT header Opcode            */°dONLNdG'<2ö*
  5743. F    FF FE                          /* PICT version -2               */°dONLNdé1<<ö*
  5744. F    00 00                          /* reserved                      */°dONLNd’;<Fö*
  5745. F    01 20 00 00                    /* HRes (Fixed)                  */°dONLNdE<Pö*
  5746. F    01 20 00 00                    /* VRes (Fixed)                  */°dONLNdcO<Zö*
  5747. F    00 00 00 00 01 F4 01 F4        /* picFrame at native resolution */°dONLNd™Y<dö*
  5748. F    00 00 00 00                    /* reserved                      */°dONLNdÒc<nö*
  5749. F    /* picture data follows                                         */°dONLNd8m<xö*
  5750. F    00 FF                          /* end of picture opcode         */
  5751. °dONLNdè<ûõ*& Random Notes
  5752. °dONLNdå™<∂‡* For information on bug fixes in °dONLNd¨™‡∂˛)§5the System Software 6.0.5 release of 32-Bit QuickDraw°dONLNd‚∂<¬≈(fiZR(version 1.2), please refer to the System Software 6.0.5 Change History, which is °dONLNd4∂≈¬˛(fi„ available on°dONLNdA¬<Œ(ÍZ&the Developer CD Series, AppleLink in °dONLNdg¬Œ˛)»0the Developer Services Bulletin Board (Developer°dONLNdòŒ<⁄û(ˆZServices: Macintosh °dONLNd¨Œû⁄˛)bEDeveloper Technical Support: System Software), and the Apple FTP site°dONLNdÚ⁄<Ê(Z/on the Internet in the ~ftp/pub/dts/sw.license.°dONLNd"Û<ˇ*,Note that the dispatching mechanism for the °dONLNdNÛˇ.)Ÿnew °dONLNdRÚ.˛Ç) _QDOffscreen°dONLNd^Ûǡ˛)T calls is slightly different°dONLNd{< Ë((Z#than previously documented; it now °dONLNdûË †)¨&requires that the high word passed in °dONLNdƒˇ† Æ)∏D0°dONLNdΔÆ ˛) contain the total°dONLNdŸ <¸(4Z*length of the parameters (in bytes).  The °dONLNd ¸˛)¿8reason for this change is that if the call is made in an°dONLNd<<$V(@Z:earlier version of 32-Bit QuickDraw, the system can strip °dONLNdvV$˛(@t!the parameters from the stack and°dONLNdò%<1[(MZreturn °dONLNdü$[0å)QDError°dONLNd¶%å1=)1) set to the caller (instead of crashing).°dONLNd–I<U¶(qZFurther Reference: tXt°dONLNd„VNbR+
  5753. •°dONLNdÂV`b±)Inside Macintosh°dONLNdıV±bC)Q, Volume V, Color QuickDraw°dONLNdbNnR(äl•°dONLNdb`nm)432-Bit QuickDraw Release Notes (available from APDA)°dONLNdHnNzR(ñl•°dONLNdJn`z)$System Software 6.0.5 Change History°dONLNdozNÜR(¢l•°dONLNdqz`Üó)
  5754. d e v e l o p°dONLNd~zóÜæ)7    , Issue I°dONLNdàí<û(∫Z*NuBus is a trademark of Texas Instruments. ◊X◊
  5755. (ÏZ'32-Bit QuickDraw:  Version 1.2 Features(Ï5) of 5ˇ§◊#ˇ ˇˇˇˇ#◊†Ç 
  5756. /ZÅ#
  5757.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  5758. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  5759. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  5760. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  5761. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  5762.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  5763. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  5764. IR.°dONLNdn<Å(õZBasic QuickDraw Q&As
  5765. °dONLNdÄ<èr*Imaging°dONLNdÄnè˛(´åM.IM.BasicQD.Q&As
  5766. °dONLNd/õ<ßt(√Z Revised by:°dONLNd;õÑߡ)HDeveloper Support Center°dONLNdTõæß˛(√‹ October 1992°dONLNdaß<≥q(œZ Written by:°dONLNdmßÑ≥ˇ)HDeveloper Support Center°dONLNdÜßæ≥˛(œ‹ October 1990°dONLNdìø<À⁄(ÁZThis Technical Note contains a °dONLNd≤ø⁄À˛)û9collection of Q&As relating to a specific topic—questions°dONLNdÏÀ<◊†(ÛZGyou’ve sent the Developer Support Center (DSC) along with answers from °dONLNd3À†◊˛(Ûæthe DSC engineers.°dONLNdF◊<„u(ˇZ
  5767. While DSC °dONLNdP◊u„˛)9Lengineers have checked the Q&A content for accuracy, the Q&A Technical Notes°dONLNdù„<Ôq( Z don’t have °dONLNd®„qÔ˛)5Qthe editing and organization of other Technical Notes. The Q&A function is to get°dONLNd˙Ô<˚Ÿ(Znew technical information and °dONLNdÔŸ˚˛)ù6updates to you quickly, saving the polish for when the°dONLNdO˚<(#Z,information migrates into reference manuals.°dONLNd|<k*:Q&As are now included with Technical Notes to make access °dONLNd∂k˛(;âto technical updates easier for°dONLNd÷<+.(GZ/you. If you have comments or suggestions about °dONLNd.+˛)Ú*Q&A content or distribution, please let us°dONLNd0+<7\(SZknow °dONLNd5+\7˛) Iby sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical°dONLNd7<Ci(_Z9questions about Q&A content to DEVSUPPORT for resolution.°dONLNdπO<[«*NNew Q&As and Q&As revised this month are marked with a bar in the side margin."n  ÜXÜ
  5768. °dONLNdÄ<è†*42Sending PostScript via PostScriptHandle PicComment
  5769. °dONLNd;è<õb* Written:°dONLNdDèàõ¶)L5/1/90°dONLNdKõ<ßÅ(√ZLast reviewed:°dONLNdZõàߨ)L10/9/91°dONLNdb≥<øG(€ZIf °dONLNde≥Gø˛) XI use the PostScriptHandle PicComment to send PostScript code to the LaserWriter driver,°dONLNdæø<À£(ÁZHdo I need to open a picture and then draw the picture to the driver, or °dONLNdø£À˛(Á¡can I just use the°dONLNdÀ<◊õ(ÛZHPicComment with no picture open while drawing to the printer’s grafPort?°dONLNdb◊<„N* ___°dONLNdfÔ<˚ò*You don’t need to °dONLNdxÔò˚˛)\Gcreate a picture with your PicComment in it and draw the picture to the°dONLNd¿˚<(#ZQdriver. The best method for sending PostScript code to the LaserWriter is to use °dONLNd˚˛(#the°dONLNd<_(/Z8PostScriptHandle PicComment documented in the Macintosh °dONLNdM_˛(/}Technical Note #91, “Optimizing°dONLNdm<V(;Z6for the LaserWriter—Picture Comments,” as shown below.,
  5770. Courier
  5771.     °dONLNd§+<6á*PrOpenPage(...)°dONLNd¥5<@c*
  5772. ;{ Send some QuickDraw so that the Printing Manager gets a }°dONLNd?<J    *
  5773. ){ chance to define the clipping region. }°dONLNdI<T}*
  5774.  
  5775. PenSize(0,0);°dONLNd)S<^x*
  5776. MoveTo(0,0);°dONLNd6]<hx*
  5777. LineTo(0,0);°dONLNdDg<r}*
  5778.  
  5779. PenSize(1,1);°dONLNdSq<|*
  5780. $PicComment(PostScriptBegin, 0, NIL);°dONLNdx{<Ü*
  5781. ({ QuickDraw representation of graphic. }°dONLNd°Ö<êë*
  5782. MoveTo(100, 100);°dONLNd≥è<öë*
  5783. LineTo(200, 200);°dONLNd≈ô<§    *
  5784. ){ PostScript representation of graphic. }°dONLNdÔ£<ÆT*
  5785. 8thePSHandle^^ := '100 100 moveto 200 200 lineto stroke'; ◊X◊
  5786. *"Basic QuickDraw Q&As(Ïˇ1) of 21ˇ°¿Ù%%DSIDICT:_cv
  5787. currentdict /bu known {bu}if
  5788. userdict /_cv known not{userdict /_cv 30 dict put}if
  5789. _cv begin
  5790. /bdf{bind def}bind def
  5791. currentscreen/cs exch def/ca exch def/cf exch def
  5792. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  5793. /ss{//cf //ca //cs setscreen}bdf
  5794. /stg{ss setgray}bdf
  5795. /strgb{ss setrgbcolor}bdf
  5796. /stcmyk{ss cvcmyk}bdf
  5797. /min1{dup 0 eq{pop 1}if}bdf
  5798. end
  5799. currentdict /bn known {bn}if
  5800. †øé◊#ˇ ˇˇˇˇ#◊ 
  5801. IR,Times
  5802. .+6-Macintosh Technical Notes /4/˘,
  5803. Courier
  5804.     °dONLNd(0*8PicComment(PostScriptHandle, GetHandleSize(thePSHandle),°dONLNd9'2ö*
  5805.               thePSHandl);°dONLNdT1<¬*
  5806. "PicComment(PostScriptEnd, 0, NIL);°dONLNdw;Fh*
  5807. PrClosePage(...)
  5808. °dONLNdàQ]C*5The above code prints a line on any type of printer, °dONLNdΩQC]⁄(yaPostScript or not. The first°dONLNd⁄]ifi(Ö6&MoveTo/LineTo combination is required °dONLNd]fii⁄)Δ3to give the LaserWriter driver a chance to define a°dONLNd4iuA(ë6    clipping °dONLNd=iAu⁄))Uregion. The LaserWriter driver replaces the grafProcs record in the grafPort returned°dONLNdìuÅ}(ù6Kfrom PrOpenDoc. In order for the LaserWriter driver to get execution time, °dONLNdfiu}Å⁄(ùõyou must execute a°dONLNdÒÅçz(©6IQuickDraw drawing routine that calls one of the grafProcs. In this case, °dONLNd:Åzç⁄(©òthe MoveTo/LineTo°dONLNdLçôç(µ6Ocombination calls the StdLine grafProc. When StdLine executes, it notices that °dONLNdõççô⁄(µ´the grafPort has°dONLNd¨ô•Ã(¡6Vbeen reinitialized, and therefore initializes the clipping region for the port. Until °dONLNdôÕ⁄(¡Íthe°dONLNd•±](Õ6CMoveTo/LineTo combination is executed, the clipping region for the °dONLNdI•]±⁄(Õ{port is set to (0,0,0,0). If°dONLNdf±Ωè(Ÿ6MPostScript code is sent via the PostScriptHandle PicComment before executing °dONLNd≥±èΩ⁄(Ÿ≠
  5809. any QuickDraw°dONLNd¡Ω…?(Â6Aroutines, all PostScript operations will be clipped to (0,0,0,0).°dONLNd’·≠*The next thing that’s done is °dONLNd!’≠·⁄)ï7to send the PostScriptBegin PicComment. This comment is°dONLNdY·Ì(    64recognized only by PostScript printer drivers. When °dONLNdç·Ì⁄)˙*the driver receives this comment, it saves°dONLNd∏Ì˘v(6the current state of °dONLNdÕÌv˘⁄)^Hthe PostScript device (by executing the PostScript gsave operator), then°dONLNd˘ã(!6disables all QuickDraw °dONLNd-˘ã⁄)sAdrawing operations. This way, the QuickDraw representation of the°dONLNdoπ(-6Igraphic will be ignored by PostScript devices. In the above example, the °dONLNd∏π⁄(-◊second°dONLNdøt(96EMoveTo/LineTo combination is executed only on non-PostScript devices.°dONLNd)5*5The next PicComment is PostScriptHandle, which tells °dONLNd:)5⁄(Q='the driver that the data in thePSHandle°dONLNdb5Aø(]6[is to be sent to the device as PostScript code. The driver then passes this code unchanged °dONLNdΩ5øA⁄(]›to the°dONLNdƒAMv(i6APostScript device for execution. The PostScriptHandle comment is °dONLNdAvM⁄(iîrecognized only by°dONLNdMYì(u6PostScript printer drivers.°dONLNd4eqD*@The last PicComment, PostScriptEnd, tells the driver to restore °dONLNdteDq⁄(çb the previous state of the device°dONLNdïq}Ü(ô6M(via a PostScript grestore call), and to enable QuickDraw drawing operations.°dONLNd„âïå*>Since most PicComments are ignored by QuickDraw devices, only °dONLNd!âåï⁄(±™
  5810. the QuickDraw°dONLNd/ï°s(Ω6Jrepresentation is printed. Since PostScriptBegin tells PostScript drivers °dONLNdyïs°⁄(Ωëto ignore QuickDraw°dONLNdç°≠h(…6operations, only °dONLNdû°h≠⁄)POthe PostScript representation is printed on PostScript devices. This is a truly°dONLNdÓ≠π≠(’6device-independent method for °dONLNd     ≠≠π⁄)ï<providing both PostScript and QuickDraw representations of a°dONLNd    Iπ≈J(·6    document.
  5811. °dONLNd    S›Ï-*''Macintosh PICT-to-PostScript conversion
  5812. °dONLNd    {ϯ>* Written:°dONLNd    ÑÏd¯Ç)L8/3/90°dONLNd    ã¯]( 6Last reviewed:°dONLNd    ö¯dà)L10/8/91°dONLNd    ¢e(86EHow do I convert PICT format data to PostScript in my printer driver?°dONLNd    Ë(** ___°dONLNd    Ï4@v*FConverting PICT files to PostScript involves a detailed understanding °dONLNd
  5813. 24v@⁄(\îof both bitmaps (or°dONLNd
  5814. F@Lª(h6#pixmaps) and the graphics state in °dONLNd
  5815. i@ªL⁄)£=PostScript, which is a data structure defining the context in°dONLNd
  5816. ßLX5(t68which other graphic operators in PostScript execute. If °dONLNd
  5817. flL5X⁄(tSyou don’t know PostScript, the°dONLNd
  5818. ˛Xd¶(Ä6following manuals are a must:°dONLNd p|‘*#• PostScript Language Tutorial and °dONLNd ?p‘|⁄)º/Cookbook (Addison-Wesley) is an introduction to°dONLNd o|ào(§6DPostScript. • PostScript Language Reference Manual (Addison-Wesley).°dONLNd ¥àî©* R• PostScript Language Program Design (Addison-Wesley) details designing efficient °dONLNd à©î⁄(∞«
  5819. PostScript°dONLNd î†∞(º6Xprograms. It has a lot of useful sample programs on topics like writing a print spooler. ◊4◊˘
  5820. *02) of 21(ÏñBasic QuickDraw Q&Asˇ0◊#ˇ ˇˇˇˇ#◊ 
  5821. IR,Times
  5822. .+Z-Developer Support Center(-Ê October 1992 /X/
  5823. °dONLNd<):(EZ1You need to convert all the QuickDraw operations °dONLNd1:)˛)˛%in a PICT to corresponding PostScript°dONLNdW)<5u(QZ operations. °dONLNdc)u5˛)9MTo get a feel for this conversion, you can analyze the PostScript dump from a°dONLNd±5<A¬(]ZKLaserWriter to see how it converts a PICT to PostScript. Under System 6.x, °dONLNd¸5¬A˛(]‡ a PostScript°dONLNd    A<M(iZUdump can be obtained by pressing Command-K while printing. Under System 7.0, you can °dONLNd^AM˛(iget°dONLNdbM<Yp(uZCa dump by selecting the PostScript File option in the Print dialog.°dONLNd¶e<qı*NSome areas of QuickDraw, such as transfer modes, do not have a correspondence °dONLNdÙeıq˛(çin°dONLNd˜q<}â(ôZGPostScript. The PostScript imaging model is designed so that all areas °dONLNd>qâ}˛(ôßof a page affected by an°dONLNdW}<ân(•Z
  5824. image are °dONLNda}nâ˛)2Lmarked as if with opaque paint. Using image masks can help. See the Graphics°dONLNdÆâ<ï(±Z+chapter in the PostScript reference manual.°dONLNd⁄°<≠*,PICT-to-PostScript conversion can be a long °dONLNd°≠˛)„-process, especially if one is unfamiliar with°dONLNd4≠<π¯(’Z&PostScript. Using the above books and °dONLNdZ≠¯π˛)º2the PostScript dump from the LaserWriter (but ONLY°dONLNdçπ<≈“(·Z as a general guide) should help.
  5825. °dONLNdÆ›<ÏD*''Calling InitCursor instead of SetCursor
  5826. °dONLNd÷Ï<¯b* Written:°dONLNdflÏà¯≤)L10/23/90°dONLNd˯<Å( ZLast reviewed:°dONLNd˜¯à¨)L2/20/91°dONLNdˇ<è(8ZGIs it legal to call InitCursor instead of SetCursor(arrow) when I want °dONLNdFè˛(8≠to set the cursor to an°dONLNd^<(å(DZarrow (after my °dONLNdnå(˛)PInormal one-time program initialization code, in my UpdateCursor routine)?°dONLNd∏(<4I(PZ6The only reason I'd want to do such a skanky thing is °dONLNdÓ(I4˛(Pg$to save code. Calling a trap with no°dONLNd4<@í(\Zparameters is less °dONLNd&4í@˛)VJcode than one with parameters. What, exactly, if anything, does InitCursor°dONLNdq@<L§(hZOdo besides setting the cursor to an arrow and setting the cursor level to zero?°dONLNd¡L<XN* ___°dONLNd≈d<pU*8There's no problem at all with this, as long as you are °dONLNd˝dUp˛(ås aware that the hidden, busy, and°dONLNdp<|Ÿ(òZ!obscured states are cleared when °dONLNd?pŸ|˛)ù<you call InitCursor, so if the cursor was hidden or obscured°dONLNd||<àA(§Z:for good reason it'll suddenly reappear. It also gets the °dONLNd∂|Aà˛(§_$arrow from QuickDraw, of course, but°dONLNd€à<îû(∞Zthat's not a problem.
  5827. °dONLNdÒ¨<ª◊*'PICT fontName opcode
  5828. °dONLNdª<«b* Written:°dONLNdªà«≤)L10/31/90°dONLNd«<”Å(ÔZLast reviewed:°dONLNd'«à”¨)L2/20/91°dONLNd/fl<Ρ(ZRIs there an up-to-date canonical source for PICT opcodes? In “Night of the Living °dONLNdÅfl¡Î˛(fl
  5829. Disc,” as far°dONLNdèÎ<˜I(Z6as I can see, the only list of PICT opcodes is in the °dONLNd≈ÎI˜˛(g Macintosh Tech Note “QuickDraw’s°dONLNdʘ<√(ZPInternal Picture Definition” which does not mention opcode $2C. It appears that °dONLNd6˜√˛(·
  5830. opcode $2C°dONLNdA<Ù(+ZRconcerns font names. I recall seeing a patch for PictDetective named "fontnameop" °dONLNdìÙ˛(+or°dONLNdñ<≠(7ZMsomething like that. However I can't be sure that $2C is the only new opcode.°dONLNd‰<'N* ___°dONLNdË3<?Ü*@The fontName opcode is documented in the Technical Note “32-Bit °dONLNd    (3Ü?˛([§QuickDraw: Version 1.2°dONLNd    ??<Kfi(gZXFeatures.” Note also that since the introduction of 32-Bit QuickDraw there are two more °dONLNd    ó?fiK˛(g¸bitmap°dONLNd    ûK<WÏ(sZQopcodes for direct RGB PixMaps $009A (DirectBitsRect) and $009B (DirectBitsRgn). °dONLNd    ÔKÏW˛(s
  5831. The°dONLNd    ÛW<cv(Z
  5832. QuickDraw °dONLNd    ˝Wvc˛):Nsection of Inside Macintosh Volume VI has all these opcodes listed in a single°dONLNd
  5833. Lc<o√(ãZRplace, making it easier to get the necessary info. Here is the info on font names °dONLNd
  5834. ûc√o˛(ã· and pictures°dONLNd
  5835. ´o<{ (óZ)from the "32-Bit QuickDraw..." Tech Note:°dONLNd
  5836. ’á<ìˆ*#PICTs Contain Font Name Information°dONLNd
  5837. ˘ü<´¢*JEvery time you draw text inside of an _OpenPicture and _ClosePicture pair, ◊X◊
  5838. *%Basic QuickDraw Q&As(Ïˇ3) of 21ˇË◊#ˇ ˇˇˇˇ#◊ 
  5839. IR,Times
  5840. .+6-Macintosh Technical Notes /4/˘
  5841. °dONLNd)É*KQuickDraw stores the name of the current font and uses it when playing back°dONLNdL)5É* Nthe picture. The opcode used to save this information is $002C and its data is°dONLNdõ5AL* as follows:,
  5842. Courier
  5843.     °dONLNdßMXê*   PictFontInfo = Record°dONLNd¿Wbv*
  5844. F                    length   : Integer;    { length of data in bytes }°dONLNdalv*
  5845. F                    fontID   : Integer;    { ID in the source system }°dONLNdNkv÷*
  5846. &                    fontName : Str255;°dONLNduuÄÜ*
  5847.                   END;
  5848. °dONLNdåãóá*EQuickDraw saves this information only one time for each font used in °dONLNd—ãáó⁄(≥•a picture. When°dONLNd·ó£X(ø6BQuickDraw plays back a picture, it uses the fontID as a reference °dONLNd#óX£⁄(øvinto the list of font names°dONLNd?£Ø*(À6<which are used to set the correct font on the target system.°dONLNd|ª«µ* For example, the following code:
  5849.     °dONLNdù”fiq*E   GetFNum('Venice', theFontID);    { Set a font before opening PICT}°dONLNd„›Ëã*
  5850.    TextFont(theFontID);°dONLNd˚Ò¸Ã*$   pHand2 := OpenPicture (pictRect);°dONLNd ˚Å*
  5851.        MoveTo(20,20);°dONLNd6€*
  5852. '       DrawString(' Better be Venice');°dONLNd^$Ã*$       GetFNum('Geneva', theFontID);°dONLNdÉ#.ü*
  5853.        TextFont(theFontID);°dONLNdü-8Å*
  5854.        MoveTo(20,40);°dONLNdµ7B§*
  5855.        DrawString('Geneva');°dONLNd“KV÷*&       GetFNum('New York', theFontID);°dONLNd˘U`ü*
  5856.        TextFont(theFontID);°dONLNd_jÅ*
  5857.        MoveTo(20,60);°dONLNd+itÆ*
  5858.        DrawString('New York');°dONLNdJ}àÃ*$       GetFNum('Geneva', theFontID);°dONLNdoáíü*
  5859.        TextFont(theFontID);°dONLNdãëúÅ*
  5860.        MoveTo(20,80);°dONLNd°õ¶§*
  5861.        DrawString('Geneva');°dONLNdæ•∞h*
  5862.    ClosePicture;
  5863. °dONLNdœª«*:generates a picture containing font information like this:
  5864.     °dONLNd
  5865. ”fi|*   OpCode 0x002C {9,°dONLNd›Ëq*
  5866. E       "0005 0656 656E 6963 65"}          /* save current font     */°dONLNdeÁÚr*
  5867.    TxFont 'venice'°dONLNdxÒ¸Â*
  5868. )   DHDVText {20, 20, " Better be Venice"}°dONLNd¢˚q*
  5869. E   OpCode 0x002C {9,                      /* save next font name   */°dONLNdË∏*
  5870.         "0003 0647 656E 6576 61"}°dONLNd    r*
  5871.    TxFont 'geneva'°dONLNd$ê*
  5872.    DVText {20, "Geneva"}°dONLNd5#.v*
  5873. F   OpCode 0x002C {11,                     /* ditto                  */°dONLNd|-8—*
  5874. %       "0002 084E 6577 2059 6F72 6B"}°dONLNd¢7Bw*
  5875.    TxFont 'newYork'°dONLNd∂ALö*
  5876.    DVText {20, "New York"}°dONLNd—KVg*
  5877. C   TxFont 'geneva'                        /* second Geneva does not°dONLNdU`g*
  5878. C                                          need another $002C guy */°dONLNdY_jê*
  5879.    DVText {20, "Geneva"}
  5880. °dONLNdruÅ•*VThis feature works regardless of the type of picture being saved, including old style °dONLNd»u•Å⁄(ù√
  5881. PICTs in a°dONLNd”Åç/(©65black-and-white port. Using _OpenCPicture instead of °dONLNdÅ/ç⁄(©M!_OpenPicture to start a recording°dONLNd*çô◊(µ6*session results in the same functionality. ◊4◊˘
  5882. *74) of 21(ÏñBasic QuickDraw Q&AsˇÊ◊#ˇ ˇˇˇˇ#◊ 
  5883. IR,Times
  5884. .+Z-Developer Support Center(-Ê October 1992 /X/
  5885. °dONLNd<)b(EZX-Refs:°dONLNd)<5ƒ* Inside Macintosh Volume VI°dONLNd#5<AÄ* BMacintosh Technical Note “QuickDraw's Internal Picture Definition”°dONLNdfA<MÑ* AMacintosh Technical Note “32-Bit QuickDraw: Version 1.2 Features”
  5886. °dONLNd®e<t*' Using PicComments to rotate text
  5887. °dONLNd…t<Äb* Written:°dONLNd“tàÄ≤)L11/28/90°dONLNd€Ä<åÅ(®ZLast reviewed:°dONLNdÍÄàå≤)L12/19/90°dONLNdÛò<§(¿Z\I have a PostScript routine (using TextBegin/TextEnd) to generate bitmapped rotated text on °dONLNdOò§˛(¿the°dONLNdS§<∞Å(ÃZscreen (which °dONLNda§Å∞˛)EOcan be later printed on QuickDraw printers). Why do I get duplicate text? I get°dONLNd±∞<º*(ÿZ3both bitmapped rotated text and PostScript rotated °dONLNd‰∞*º˛)Ó,text when I print on the LaserWriter II, and°dONLNdº<»Ö(‰ZDboth bitmapped rotated text and horizontal text on the ImageWriter. °dONLNdUºÖ»˛(‰£When I make a machine°dONLNdk»<‘o(Z
  5888. dependent °dONLNdu»o‘˛)3Tcheck (check type of printer) and call the proper printing procedure, it works fine.°dONLNd ‘<‡5(¸Z/Because of the speed and memory considerations °dONLNd˘‘5‡˛)˘(of generating the rotated bitmapped text°dONLNd"‡<Ï—(Z[(especially at 300 dpi), is there a way to ensure that the printer will use the PostScript °dONLNd}‡—Ï˛(ÔBEFORE°dONLNdÑÏ<¯¶(Zgenerating the bitmap?°dONLNdõ¯<N* ___°dONLNdü<z* We will use °dONLNd´z˛)>Ithe following Macintosh PicComments to hide your QuickDraw calls from the°dONLNdı<((DZ/LaserWriter, but the ImageWriter will use them:,
  5889. Courier
  5890.     °dONLNd%4<?á*PostScriptBegin°dONLNd5><Iw*
  5891. ? >> Put your CopyBits and QuickDraw calls to image your rotated°dONLNduH<S√*
  5892.  >> bitmapped text here....°dONLNdëR<]}*
  5893.  
  5894. PostScriptEnd
  5895. °dONLNdüh<t®*By wrapping your °dONLNd∞h®t˛)l;QuickDraw code within the PostScriptBegin and PostScriptEnd°dONLNdÏt<Ä€(úZSPicComments, the code will be ignored by the LaserWriter, but the ImageWriter will °dONLNd?t€Ä˛(ú˘use the°dONLNdGÄ<å(®ZSQuickDraw calls. Basically, the PostScriptBegin and PostScriptEnd PicComments tell °dONLNdöÄå˛(®the°dONLNdûå<òÔ(¥ZZLaserWriter driver to turn “off” QuickDraw. In the ImageWriter case, the ImageWriter does °dONLNd¯åÔò˛(¥
  5896. not°dONLNd¸ò<§¨(¿ZJunderstand the PicComments. Therefore, it will use the QuickDraw calls to °dONLNdFò¨§˛(¿ create and image°dONLNdW§<∞û(ÃZyour bitmapped text.°dONLNdmº<»!*-Now, we need to use the rotation PicComments °dONLNdöº!»˛)Â/to rotate the text on the LaserWriter, but have°dONLNd »<‘÷(Z the ImageWriter ignore the code:
  5897.     °dONLNd·<Îá*Rect  zeroRect;°dONLNd˚Ù<ˇ‹* SetRect (&zeroRect, 0, 0, 0, 0);°dONLNd<i*    TextBegin°dONLNd&<n*
  5898.  
  5899. TextCenter°dONLNd1<'√*
  5900.       ClipRect (&zeroRect);°dONLNdM0<;h*<      >> Draw your text to be rotated on the LaserWriter....°dONLNdäD<O»*      ClipRect (&rPageRect);°dONLNdßN<Y_*
  5901. TextEnd
  5902. °dONLNdØd<p‘*XWrapping your text drawing call(s) between the ClipRect calls will ensure that the text °dONLNdd‘p˛(åÚis drawn°dONLNdp<|Û(òZVonly on the LaserWriter. Setting the ClipRect to zero tells the ImageWriter to ignore °dONLNdfpÛ|˛(òall°dONLNdj|<àæ(§ZQuickDraw calls until the °dONLNdÑ|æà˛)Ç@ClipRect is reset to something “real” (actually, a zero ClipRect°dONLNd≈à<îΩ(∞Zprevents QuickDraw from °dONLNd›àΩî˛)Å>drawing anything). After we have completed drawing the rotated°dONLNd    î<†«(ºZtext, we reset the ClipRect to °dONLNd    ;˛)ãAthe dimensions of rPage (that is, rPage is the image-able area of°dONLNd    }†<¨n(»Z@the currently selected printer—see Inside Macintosh, Volume II, °dONLNd    Ω†n¨˛(»åpage 150). This will allow all ◊X◊
  5903. (ÏZBasic QuickDraw Q&As(Ïˇ5) of 21ˇ0◊#ˇ ˇˇˇˇ#◊ 
  5904. IR,Times
  5905. .+6-Macintosh Technical Notes /4/˘
  5906. °dONLNd)b*of your normal °dONLNdb)⁄)JLdrawing to continue on the ImageWriter and LaserWriter. If you did not reset°dONLNd\)5ÿ(Q6%the ClipRect after the TextEnd call, °dONLNdÅ)ÿ5⁄)¿,nothing would be drawn on the ImageWriter or°dONLNdÆ5AT(]6 LaserWriter.
  5907. °dONLNdªYhO*'*Using dithered drawing mode with QuickDraw
  5908. °dONLNdÊht>* Written:°dONLNdÔhdté)L11/28/90°dONLNd¯tÄ](ú6Last reviewed:°dONLNdtdÄé)L12/19/90°dONLNdåòÆ(¥6NWhen I draw a 32-bit Macintosh PICT image from a file to an 8-bit port via an °dONLNd^åÆò⁄(¥à   offscreen°dONLNdhò§ (¿67GWorld, I use dither mode in the CopyBits call and the °dONLNdüò §⁄(¿>)results are quite impressive. If there is°dONLNd…§∞o(Ã6Dnot enough memory to allocate the GWorld, I draw the image directly °dONLNd
  5909. §o∞⁄(Ãçto the port. But since°dONLNd$∞º⁄(ÿ6*there does not seem to be any way to tell °dONLNdN∞⁄º⁄)¬1QuickDraw to use dithered drawing mode, the image°dONLNdĺ»^(‰6looks horrible.°dONLNdꑇ(*9Do you have any suggestions? I have installed bottleneck °dONLNd…‘(‡⁄(¸F%procs to allow DrawPicture to get its°dONLNdԇπ(6,data from the file instead of the handle in °dONLNd‡€Ï⁄)√4memory. Is there a way, while in the bottlenecks, to°dONLNdPϯ—(6'find the CopyBits call that comes from °dONLNdwÏ—¯⁄)π8the picture and force it to use dithered mode instead of°dONLNd∞¯o( 6Bsource mode? I don’t want to try and parse the PICT myself, but I °dONLNdÚ¯o⁄( çthought that maybe a°dONLNdë(,6QuickDraw global could °dONLNdë⁄)yAbe modified in my StdBits proc to force dithered drawing for that°dONLNd`a(86operation only?°dONLNdp(** ___°dONLNdt4@Ã*^You can install a StdBits or bitsProc bottleneck procedure to get all the CopyBits calls when °dONLNd“4Ã@⁄(\Íthe°dONLNd÷@L{(h6Kpicture is being played back. One of the parameters to the StdBits call is °dONLNd!@{L⁄(hôthe mode. You can°dONLNd3LX8(t6install °dONLNd;L8X⁄) Sa procedure that saves the current mode, and then passes ditherMode to the original°dONLNdèXdï(Ä6PStdBits proc. This is all you should need to do. It’s been done here so we know °dONLNdflXïd⁄(Ä≥it works, only°dONLNdÓdpQ(å6Dnot in any form that can be sent to you as sample code at this time.
  5910. °dONLNd3àó9*'(Code for reversing Macintosh PICT images
  5911. °dONLNd\ó£>* Written:°dONLNdeód£Ç)L3/4/91°dONLNdl£Ø](À6Last reviewed:°dONLNd{£dØà)L8/30/91°dONLNdɪ«F(„6 Is there a °dONLNdéªF«⁄).Psimple way to put PICT images up in mirror image format, or is there sample code°dONLNdfl«”›(Ô6(showing how to flip an offscreen bitmap?°dONLNd”fl** ___°dONLNd Θã*KThere is no easy way to do this, nor do we have sample code showing how to °dONLNdWÎã˜⁄(©flip an offscreen°dONLNdi˜ø(6#bitmap. Indeed, the best way to do °dONLNdå˜ø⁄)ß9what you want is to draw it to an offscreen pixel map and°dONLNdΔG(+6 reverse it.°dONLNd“'Ñ*If you are using Color °dONLNdÈÑ'⁄)lEQuickDraw, always draw it to an 8-bit-per-pixel offscreen bitmap, and°dONLNd/'3Ã(O6(then the reverse is a very simple task. °dONLNdW'Ã3⁄)¥5Here is some sample Pascal code that might roughly do°dONLNdç3?˝([6.what you want, with the following assumptions:°dONLNdºKW7*=    1. You are going to add error checking where appropriate.°dONLNd˙Wc9* >    2. Rowbytes correspond exactly to pixel width of the port.°dONLNd    9coû*     3. The port is 8 bits deep.°dONLNd    Yo{* 1    4. You add the code to make this sketch work.°dONLNd    ã{á˜* 2    5. The origin of your offscreen port is (0,0).,
  5912. Courier
  5913.     °dONLNd    æìû+*7Procedure FlipScanLine(theV:Integer; thePort:cGrafPtr);°dONLNd    ˆù®î*
  5914. L{ Given any scan line number in the indicated port, this routine will flip } ◊4◊˘
  5915. *(6) of 21(ÏñBasic QuickDraw Q&Asˇd◊#ˇ ˇˇˇˇ#◊ 
  5916. IR,Times
  5917. .+Z-Developer Support Center(-Ê October 1992 /X/,
  5918. Courier
  5919.     °dONLNd<(∏(DZL{ that scan line horizontally. This routine assumes that you have made     }°dONLNdM'<2*
  5920. ${ sure that scan line theV exists. }°dONLNdr;<F*(type ScanLn=Packed Array [0..0] of Byte;°dONLNdõE<P•*
  5921.    ScanPtr=^ScanLine;°dONLNd±O<Z¥*
  5922. var thePixMap:PixMapPtr;°dONLNd Y<d™*
  5923.    Index,Size:Integer;°dONLNd·c<n¥*
  5924.    ThisScanLine:ScanPtr;°dONLNd˙m<xñ*
  5925.    TempPixel:Byte;°dONLNd
  5926. Å<åU*Begin°dONLNdã<ñ·*
  5927. ! thePixMap:=thePort^.PortPixMap^;°dONLNd5ï<†ü*
  5928. G{ First create a pointer to the scan line we are currently reversing. }°dONLNd}ü<™*
  5929. , ThisScanLine:=ScanPtr(thePixMap^.BaseAddr);°dONLNd™©<¥ö*
  5930. F ThisScanLine:=ScanPtr(ord4(ThisScanLine)+(thePixMap^.RowBytes*theV));°dONLNdÒΩ<»ı*%{ Now simply reverse all the bytes. }°dONLNd«<“Ω*
  5931. M{ The scan line is simply an array [0..RowBytes] of Byte, and since this is }°dONLNde—<‹,*
  5932. 0{ 8 bits per pixel, each one is a single pixel.}°dONLNdñ€<Ê√*
  5933.  Size:=thePixMap^.RowBytes;°dONLNd≤Â<‹*
  5934.   For Index:=0 to (Size div 2) do°dONLNd”Ô<˙_*
  5935.   begin°dONLNd€˘<Î*
  5936. #   tempPixel:=ThisScanLine^[Index];°dONLNdˇ<@*
  5937. 4   ThisScanLine^[Index]:=ThisScanLine[Size-Index-1];°dONLNd4
  5938. <Î*
  5939. #   ThisScanLine^[Index]:=tempPixel;°dONLNdX<"Z*
  5940.   end;°dONLNd_!<,P*
  5941. end;
  5942. °dONLNdd7<C¬*This same procedure can be °dONLNd7¬C˛)ÜAused also to swap a 1-, 2- or 4-bit-per-pixel pixmap if you add a°dONLNd¡C<O9(kZ8function that accepts a byte and swaps the pixels in it.
  5943. °dONLNd˙g<vª*'7Use srcOr instead of srcCopy for Macintosh text drawing
  5944. °dONLNd2v<Çb* Written:°dONLNd;vàǶ)L6/4/91°dONLNdBÇ<éÅ(™ZLast reviewed:°dONLNdQÇàé¨)L10/9/91°dONLNdYö<¶=(¬Z1DrawText with srcCopy takes six times as long as °dONLNdäö=¶˛(¬[#with srcOr now that my Macintosh is°dONLNdƶ<≤w(ŒZArunning System 7. Why is this so slow? Is this a bug in System 7?°dONLNd≤<æN* ___°dONLNdÙ <÷Æ*It’s true that srcCopy is °dONLNd Æ÷˛)rDslower than srcOr when handling text, especially in color mode. This°dONLNdS÷<‚(˛Z&loss in speed occurs because CopyBits °dONLNdy÷‚˛)Δ2is a lot smarter than it used to be. It can handle°dONLNd¨‚<Ó®(
  5945. ZLforeground and background colors a lot better, but that improvement came at °dONLNd¯‚®Ó˛(
  5946. Δthe cost of speed.°dONLNd Ó<˙=(Z4Our recommended method for drawing text is to erase °dONLNd?Ó=˙˛([&before drawing, and use srcOr to draw,°dONLNdf˙<‘("ZSnot srcCopy. Alternatively, you could draw colorized text in srcOr mode off screen °dONLNdπ˙‘˛("Úand then°dONLNd¬<¶(.ZKuse CopyBits to draw it on the screen in srcCopy mode without colorization.
  5947. °dONLNd*<9>*'%Techniques for graying Macintosh text
  5948. °dONLNd49<Eb* Written:°dONLNd=9àE¶)L6/3/91°dONLNdDE<QÅ(mZLast reviewed:°dONLNdSEàQ¶)L8/1/91°dONLNdZ]<iÅ(ÖZBHow do I draw grayed-out text on the Macintosh, like the text for °dONLNdú]Åi˛(Öüdisabled buttons or menu°dONLNdµi<uZ(ëZitems?°dONLNdºu<ÅN* ___°dONLNd¿ç<ôy*FThere are currently two different kinds of grayed text: First, there’s ◊X◊
  5949. *7Basic QuickDraw Q&As(Ïˇ7) of 21ˇ(◊#ˇ ˇˇˇˇ#◊ 
  5950. IR,Times
  5951. .+6-Macintosh Technical Notes /4/˘
  5952. °dONLNd)ƒ*$“patterned” gray, where every other °dONLNd$ƒ)⁄)¨8dot is missing. This really only looks good with Chicago°dONLNd])5-(Q65or other heavy fonts and was always used for graying °dONLNdí)-5⁄(QK out menus and controls in system°dONLNd≥5A(]66software through 6.0.x, and is still used in 7.0 when °dONLNdÈ5A⁄)˝+the screen is set to less than 4 bits deep.°dONLNdAM∞(i6This is done by first drawing °dONLNd3A∞M⁄)ò8the text in a normal, srcCopy transfer mode. Then a gray°dONLNdlMYq(u6rectangle is drawn °dONLNdMqY⁄)YMover the text using the patBic mode. This “erases” half the bits in the text,°dONLNdÕYe(Å6:and is rapid enough that there is very rarely any flicker.°dONLNdq}(*<The second kind of text is the actually gray text, which is °dONLNdDq(}⁄(ôF$used in System 7 on screens that are°dONLNdi}âÑ(•6J4 bits deep or deeper for menus, controls, and other grayed text. To draw °dONLNd≥}Ñâ⁄(•¢this text, just call°dONLNd»âïÑ(±6HGetGray (as documented on page 17-27 of Inside Macintosh, Volume VI) to °dONLNdâÑï⁄(±¢get an appropriate°dONLNd#ï°À(Ω6'gray. Then draw the text in that color.
  5953. °dONLNdKπ»Ñ*'3Updating Macintosh cursor without mouse competition
  5954. °dONLNd»‘>* Written:°dONLNdà»d‘à)L6/12/91°dONLNdꑇ](¸6Last reviewed:°dONLNdü‘d‡Ç)L8/1/91°dONLNd¶Ï¯ (6WHow can I programmatically move the Macintosh mouse without the real mouse interfering?°dONLNd˛¯** ___°dONLNdq*GThe real answer to your question is twofold: First, you can do exactly °dONLNdIq⁄(8èwhat you want to do°dONLNd](d(D6Bwith the sample included below. HOWEVER, this is not a good thing °dONLNdüd(⁄(DÇto do, it would be better°dONLNdπ(4O(P6 if you took °dONLNd≈(O4⁄)7Othe solution used in Apple’s Guided Tour disks: Always hide the cursor and then°dONLNd4@Á(\6*decouple the cursor from the mouse. Then, °dONLNd?4Á@⁄)œ1instead of using the system’s cursor, simply draw°dONLNdq@L(h64your own “cursor” using QuickDraw and treat it as a °dONLNd•@L⁄)˚*little animated bitmap on the screen. This°dONLNd–LX(t6/avoids all the problems that you have with the °dONLNdˇLX⁄)Ì'mouse competing. (Apple does update the°dONLNd'Xdã(Ä6Omouse globals with the mouse position so that other things function correctly.)°dONLNdwp|≠*PNow, as promised, here is the way to do what you want using the real cursor. As °dONLNd«p≠|⁄(òÀyou have°dONLNd–|à(§65discovered, setting the crsrCouple variable to false °dONLNd|à⁄)ˇ&prohibits the mouse from affecting the°dONLNd,àîB(∞6?cursor; unfortunately, it also prohibits the jcrsrTask routine °dONLNdkàBî⁄(∞`from drawing the cursor. The°dONLNdà(º60solution to this is to set crsr couple to true, °dONLNd∏⁄)Ã3call the cursor drawing routine jCrsrTask yourself,°dONLNdφ¨<(»6>and then set the crsrCouple variable to false, as shown below:,
  5955. Courier
  5956.     °dONLNd+∏√w*procedure callcrsr;°dONLNd?¬ÕÂ*
  5957. )              inline $2078 ,$08EE ,$4E90;°dONLNdiÃ◊«*
  5958. #{            move.L    jcrsrTask,A0°dONLNdç÷·*
  5959. 4            jsr    (A0)                            }°dONLNd¬ÍıÅ*Procedure FudgeMouse;°dONLNdÿ˛    ê*type    PointPtr=^Point;°dONLNdÒ©*var        RawMouse:PointPtr;°dONLNd    'ã*
  5960.         MTemp:PointPtr;°dONLNd    '&1Å*
  5961.         RandPt:Point;°dONLNd    =0;|*
  5962.         CrsrNew:ptr;°dONLNd    R:Eã*
  5963.         CrsrCouple:ptr;°dONLNd    jDOÅ*
  5964.         fred:Longint;°dONLNd    àXc1*begin°dONLNd    ébmΩ*
  5965. !        RawMouse:=PointPtr($82C);°dONLNd    ∞lwÆ*
  5966.         MTemp:=PointPtr($828);°dONLNd    œvÅü*
  5967.         CrsrNew:=ptr($8CE);°dONLNd    ÎÄãÆ*
  5968.         CrsrCouple:=ptr($8CF);°dONLNd
  5969.  
  5970. äïö*
  5971.         RandPt:=RawMouse^;°dONLNd
  5972. %îü^*
  5973.         repeat°dONLNd
  5974. 4û©Ω*
  5975. !            RandPt.h:=RandPt.h+1; ◊4◊˘
  5976. *'8) of 21(ÏñBasic QuickDraw Q&Asˇfi◊#ˇ ˇˇˇˇ#◊ 
  5977. IR,Times
  5978. .+Z-Developer Support Center(-Ê October 1992 /X/,
  5979. Courier
  5980.     °dONLNd<(·(DZ!            RandPt.V:=RandPt.v+1;°dONLNd"'<2“*
  5981.             RawMouse^:=RandPt;°dONLNdA1<<√*
  5982.             MTemp^:=RandPt;°dONLNd];<F¥*
  5983.             CrsrNew^:=1;°dONLNdvE<P√*
  5984.             CrsrCouple^:=1;°dONLNdíO<Z•*
  5985.             callCrsr;°dONLNd®Y<d√*
  5986.             crsrCouple^:=0;°dONLNdƒc<n*
  5987. (            repeat until fred<tickCount;°dONLNdÌm<x“*
  5988.             fred:=tickCount+3;°dONLNd w<Ç•*
  5989.         until Button;°dONLNd"Å<åØ*
  5990.         crsrCouple^:=1;°dONLNd:ã<ñP*
  5991. end;
  5992. °dONLNd?≠<ºg*&'System 7 QuickDraw DrawText performance
  5993. °dONLNdgº<»b* Written:°dONLNdpºà»¨)L11/4/91°dONLNdx»<‘Å(ZLast reviewed:°dONLNdá»à‘≤)L11/27/91°dONLNdê‡<Ï^(ZWe’ve °dONLNdñ‡^Ï˛)"Rnoticed that using DrawText is much slower in System 7, especially when drawing in°dONLNdÈÏ<¯¢(Zcolor (anything other °dONLNdˇÏ¢¯˛)fFthan black on white). What can be done to restore the drawing speed to°dONLNdF¯<ã( ZSystem 6 levels?°dONLNdW<N* ___°dONLNd[<(ê*9A QuickDraw function like DrawString or DrawText will be °dONLNdîê(˛(DÆslower under certain°dONLNd©(<4∑(PZMcircumstances in System 7 than System 6. Specifically, if you are drawing in °dONLNdˆ(∑4˛(P’ srcCopy mode°dONLNd4<@‚(\ZVand you colorize the text—that is, foreground color is not black and background color °dONLNdY4‚@˛(\is not°dONLNd`@<LÅ(hZ>white (Inside Macintosh Volume VI, page 17-16)—then QuickDraw °dONLNdû@ÅL˛(hüreally slows down as you°dONLNd∑L<X¬(tZMhave noticed. SOMETIMES, the speed of drawing is 6 times as slow as System 6.°dONLNdd<pt*<The cause of this slowness is a known System 7 bug. The bug °dONLNdAdtp˛(åíhas concerned the engineers°dONLNd]p<|ã(òZHgreatly and will be responded to in an appropriate manner in the future.°dONLNd¶à<îÖ*BThere are a few workarounds: One, you can avoid using the srcCopy °dONLNdËàÖî˛(∞£mode and use the default°dONLNdî<†Í(ºZ"srcOr mode instead. However, this °dONLNd#î͆˛)Æ6is not a real workaround, since you may have essential°dONLNdZ†<¨q(»Z reasons to °dONLNde†q¨˛)5Luse srcCopy. The other option is to create an offscreen pixmap or GWorld and°dONLNd≤¨<∏˚(‘Z&perform a DrawText with srcOr to this °dONLNdÿ¨˚∏˛)ø1GWorld with colorization. Then, you can perform a°dONLNd
  5994. ∏<ƒé(‡Z@CopyBits from the offscreen to the screen with srcCopy mode and °dONLNdJ∏éƒ˛(‡¨no colorization. Using°dONLNdaƒ<–»(ÏZSCopyBits will not cost you much time. Again, this is a workaround and is not ideal.°dONLNd∂‹<ËÎ*[The srcOr is a bit slower than in System 6.0.x, but it does not have a bug; rather it is a °dONLNd‹Î˲(    side°dONLNdË<Ù_(Z=effect of system enhancements. The slow speed is a trade-off °dONLNdSË_Ù˛(}"taken to receive the host of other°dONLNdvÙ<e(Z    benefits.
  5995. °dONLNdÄ<'˝*'Macintosh animation samples
  5996. °dONLNdú'<3b* Written:°dONLNd•'à3¨)L11/6/91°dONLNd≠3<?Å([ZLast reviewed:°dONLNdº3à?¨)L11/6/91°dONLNdƒK<W~(sZBDo you have an example of flicker-free animation on the Macintosh?°dONLNdW<cN* ___°dONLNd o<{*'We have some good stuff that’s written °dONLNd2o{˛)“(in MPW Pascal. It’s DTS Sample Code #16,°dONLNd[{<áv(£Z OffSample, °dONLNdf{vá˛):Land this uses some routines defined in DTS Sample Code #15, OffScreen. Also,°dONLNd≥á<ìö(ØZFthe System 7.0 CD sample code folder contains a smaller sample called °dONLNd˘áöì˛(Ø∏“GMonde” that uses°dONLNd     ì<ül(ªZGWorlds. ◊X◊
  5997. *1Basic QuickDraw Q&As(Ïˇ9) of 21ˇ\◊#ˇ ˇˇˇˇ#◊ 
  5998. IR,Times
  5999. .+6-Macintosh Technical Notes /4/˘
  6000. °dONLNd)8‚*'CopyBits bug and workaround
  6001. °dONLNd8D>* Written:°dONLNd%8dDà)L6/26/91°dONLNd-DP](l6Last reviewed:°dONLNd<DdPà)L8/13/91°dONLNdD\hß(Ñ6UHas anyone run across what I’m told is a bug in CopyBits? It works like this: In the °dONLNdô\ßh⁄(Ñ≈
  6002. deep, dark°dONLNd§ht•(ê6workings of CopyBits, some °dONLNdøh•t⁄)ç@routine tries to read the two bytes preceding the baseAddress of°dONLNdtÄ(ú66the source PixMap. If the baseAddress is at the start °dONLNd6tÄ⁄)¯)of a card’s NuBus space and there isn’t a°dONLNd`Äå’(®6]card filling the adjacent space, this causes a bus error! Has anyone found a good workaround?°dONLNdæåò** ___°dONLNd¬§∞≥*SThe short answer is: you’re right. QuickDraw inadvertently reads from memory below °dONLNd§≥∞⁄(×the base°dONLNd∞º¿(ÿ6Yaddress of a pixmap. The workaround is to place the video base address 32 bytes into the °dONLNdw∞¿º⁄(ÿfiRAM°dONLNd{º»(‰68on the card; if the card you’re using doesn’t have this °dONLNd≥º»⁄)˛&workaround, there’s nothing you can do°dONLNd⁄»‘1(6=other than making sure there’s a card in the next-lower slot.
  6003. °dONLNdÏ˚D*'+Macintosh picture (PICT) 90-degree rotation
  6004. °dONLNdD˚>* Written:°dONLNdM˚dà)L7/23/91°dONLNdU](/6Last reviewed:°dONLNdddà)L8/30/91°dONLNdl+}(G6The trick for rotating °dONLNdÉ}+⁄)eHa Macintosh QuickDraw picture 90 degrees is to intercept all bottlenecks°dONLNdÃ+7¢(S6Tand exchange the x and y coordinates. Then, call OpenPicture to receive the rotated °dONLNd +¢7⁄(S¿
  6005. picture, call°dONLNd.7C,(_6:DrawPicture(unrotatedPicture), and then call ClosePicture °dONLNdh7,C⁄(_J$on the rotated picture. You’re done!°dONLNdçCOm(k6QuickDraw spins °dONLNdùCmO⁄)UJout the DrawPicture call into its component parts, but runs each component°dONLNdËO[‡(w6+through the bottlenecks first, so they get °dONLNdO‡[⁄)»1rotated (by YOUR bottleneck intercepts) and stuck°dONLNdE[g≈(É6&into the new picture, already rotated.°dONLNdlsS*>Here‘s a bottleneck intercept for StdLine that rotates a PICT °dONLNd™sS⁄(õqcomposed entirely of Line°dONLNdƒã(ß64commands (which depend on the current pen position):,
  6006. Courier
  6007.     °dONLNd˘ó¢«*#procedure MyLineProc(newPt: point);°dONLNd°¨'*
  6008. var°dONLNd!´∂r*
  6009.   tempV : integer;°dONLNd4µ¿1*
  6010. begin°dONLNd:ø ä*
  6011. J  tempV := thePort^.pnLoc.v;     { Swap current pen location coordinates }°dONLNdÖ…‘€*
  6012. '  thePort^.pnLoc.v := thePort^.pnLoc.h;°dONLNd≠”fi§*
  6013.   thePort^.pnLoc.h := tempV;°dONLNdÕÁÚä*J  tempV := newPt.v;          { Swap destination pen location coordinates }°dONLNdÒ¸Å*
  6014.   newPt.v := newPt.h;°dONLNd.˚w*
  6015.   newPt.h := tempV;°dONLNdEm*  StdLine(newPt);°dONLNdZ#.ä*J  tempV := thePort^.pnLoc.v;  { Restore current pen location coordinates }°dONLNd•-8€*
  6016. '  thePort^.pnLoc.v := thePort^.pnLoc.h;°dONLNdÕ7B§*
  6017.   thePort^.pnLoc.h := tempV;°dONLNdÍAL,*
  6018. end;
  6019. °dONLNdÔWc”**Notice that the start coordinates as well °dONLNdW”c⁄)ª5as the destination coordinates must be swapped before°dONLNdOcoZ(ã6Bcalling StdLine. The resulting pen location is swapped back again °dONLNdëcZo⁄(ãxafter the operation, so the°dONLNd≠o{@(ó6?port looks like it should if unrotated drawing were performed. °dONLNdÏo@{⁄(ó^For things that don’t depend on°dONLNd     {á(£6=the current pen location, things are simplified a little bit. ◊4◊˘
  6020. *I10)
  6021.  of 21(ÏñBasic QuickDraw Q&Asˇ8◊#ˇ ˇˇˇˇ#◊ 
  6022. IR,Times
  6023. .+Z-Developer Support Center(-Ê October 1992 /X/
  6024. °dONLNd<)—(EZRYou’ll still need bitmap rotation code for the StdBits and StdText intercepts.You °dONLNdR—)˛(EÔmight do°dONLNd[)<5í(QZLStdText by setting the port to an offscreen one you create earlier, calling °dONLNdß)í5˛(Q∞QuickDraw’s StdText,°dONLNdº5<Aë(]ZKand then calling your bitmap rotation code to copy it into the destination.
  6025. °dONLNdY<h°*'3Macintosh QuickDraw and pen characteristic routines
  6026. °dONLNd<h<tb* Written:°dONLNdEhàt¨)L8/12/91°dONLNdMt<ÄÅ(úZLast reviewed:°dONLNd\tàĨ)L11/6/91°dONLNddå<ò"(¥Z-When generating pictures and then looking at °dONLNdëå"ò˛)Ê)the corresponding Macintosh PICT file, we°dONLNdªò<§v(¿Z?notice that QuickDraw is optimizing PnMode, PnPat, and PnSize. °dONLNd˙òv§˛(¿îCan you tell us how to stop°dONLNd§<∞∂(ÃZHQuickDraw from optimizing, and how to know when QuickDraw will optimize?°dONLNd_∞<ºN* ___°dONLNdc»<‘≥*NQuickDraw does not optimize away new pen characteristic routines, but it does °dONLNd±»≥‘˛(—insert them into°dONLNd¬‘<‡d(¸Z    pictures °dONLNdÀ‘d‡˛)(Ujust before a drawing routine that uses the pen rather than place them where they are°dONLNd!‡<Ï‘(ZVcalled. Therefore, you may not see your new pen characteristic routine until later in °dONLNdw‡‘Ï˛(Ú    a picture°dONLNdÅÏ<¯ñ(Zwhen it is about to °dONLNdïÏñ¯˛)ZKbe used. Opcodes for pen characteristics are inserted into the picture when°dONLNd·¯<:( Z5they are changed from the previous time they’re used.
  6027. °dONLNd<+∫*'8Detecting whether application window is partially hidden
  6028. °dONLNdP+<7b* Written:°dONLNdY+à7¨)L9/26/92°dONLNda7<CÅ(_ZLast reviewed:°dONLNdp7àC¨)L1/27/92°dONLNdxO<[#(wZ3We draw directly to the screen to gain the fastest °dONLNd´O#[˛)Á*possible animation speed, and when we need°dONLNd÷[<g˜(ÉZ#compatibility—such as when windows °dONLNd˘[˜g˛)ª3overlap or for multiple screens—we do use CopyBits.°dONLNd-g<sŸ(èZXHow do we tell whether the window is hidden or that the visible part is not rectangular?°dONLNdÜs<N* ___°dONLNdäã<óï*If your window is °dONLNdúãïó˛)YJcovered partially by another applications window or if your layer has been°dONLNdÁó<£≥(øZJhidden by the process menu, the visRgn of your window’s grafport will not °dONLNd1ó≥£˛(ø—be the portRect°dONLNdA£<Øm(ÀZ    anymore. °dONLNdJ£mØ˛)1P(Keep in mind that if you scroll by modifying the portRect of the grafport, then°dONLNdõØ<ªO(◊Z;you’ll have to do a more complex calculation...) Here is a °dONLNd÷ØOª˛(◊m&small Pascal routine that returns this°dONLNd˝ª<«v(„Z information:,
  6029. Courier
  6030.     °dONLNd
  6031. ”<fi"*.Function UseCopyBits(thePort:grafptr):Boolean;°dONLNd9Á<ÚU*begin°dONLNdC˚<^*:     UseCopyBits:= NOT( (thePort^.VisRgn^^.rgnSize=10) and°dONLNd~<T*
  6032. 8        (thePort^.visRgn^^.RgnBBox=thePort^.PortRect) );°dONLNd∑<P*
  6033. end;°dONLNdº#<.≥*KThe rect strucRgn^^.rgnBBox will be zero for a visible window if the system°dONLNd    -<8√*
  6034. has hidden the application.
  6035. °dONLNd%O<^b*&,How to tell whether GetPictInfo is available
  6036. °dONLNdR^<jb* Written:°dONLNd[^àj≤)L12/16/91°dONLNddj<vÅ(íZLast reviewed:°dONLNdsjàv¨)L2/24/92°dONLNd{Ç<é{(™Z How do you °dONLNdÜÇ{é˛)?Pdetermine whether the function GetPictInfo is available? Gestalt doesn’t seem to°dONLNd◊é<öû(∂Zhave the right stuff?!°dONLNdÓö<¶N* ___ ◊X◊
  6037. **Basic QuickDraw Q&As(Ï˙11)
  6038.  of 21ˇ‹◊#ˇ ˇˇˇˇ#◊ 
  6039. IR,Times
  6040. .+6-Macintosh Technical Notes /4/˘
  6041. °dONLNd)5*$0To determine whether the GetPictInfo routine is °dONLNd0)5⁄)Î*available, check the system version number°dONLNd[5A∑(]6Vwith the Gestalt function. The GetPictInfo routine is available under system software °dONLNd±5∑A⁄(]’version°dONLNdπAMt(i67.0 and later. Use °dONLNdÃAtM⁄)\Ithe Gestalt selector gestaltSystemVersion to determine the version of the°dONLNdMYA(u6>system currently running. In most cases you shouldn’t rely on °dONLNdTMAY⁄(u_the system version to determine°dONLNdtYe˘(Å62if features are available. However, in this case, °dONLNd¶Y˘e⁄)·0this is the only way to determine if the Picture°dONLNd◊eq¢(ç6Utilities Package is available.°dONLNd˜}âú*JSee Inside Macintosh Volume VI page 3-42 for information on using Gestalt °dONLNdA}úâ⁄(•∫ to check the°dONLNdNâï6(±66System version number. See Inside Macintosh Volume VI °dONLNdÑâ6ï⁄(±T page 18-3 for information on the°dONLNd•ï°è(Ω6Picture Utilities Package.°dONLNd¿≠π∂*ZFor example, the following C function will determine if the GetPictInfo call is available:,
  6042. Courier
  6043.     °dONLNd≈–ü*    #include <GestaltEQU.h>°dONLNd7Ÿ‰∏*     Boolean IsGetPictInfoAvail()°dONLNdX„Ó1*
  6044.     {°dONLNd^̯h*
  6045.       OSErr err;°dONLNdo˜w*
  6046.       long feature;°dONLNdÉ &*6         err = Gestalt(gestaltSystemVersion,&feature);°dONLNd∫*Ù*,      /*-- check for system 7 and above --*/°dONLNdÁ)4—*
  6047. %      return (feature >= 0x00000700);°dONLNd
  6048. 3>1*
  6049.     }°dONLNdGRï*or, if you prefer Pascal:°dONLNd-[fÂ*)    function IsGetPictInfoAvail: Boolean;°dONLNdWep;*
  6050.     var°dONLNd_ozw*
  6051.         err: OSErr;°dONLNdsyÑï*
  6052.         feature: longint;°dONLNdçÉéE*
  6053.         begin°dONLNdóçò&*
  6054. 6        err := Gestalt(gestaltSystemVersion, feature);°dONLNdŒó¢˛*
  6055. .        (*-- check for system 7 and above --*)°dONLNd˝°¨!*
  6056. 5        IsGetPictInfoAvail := (feature >= $00000700);°dONLNd3´∂@*
  6057.     end;
  6058. °dONLNd<Õ‹ı*&!GrafPort patStretch: valid values
  6059. °dONLNd^‹Ë>* Written:°dONLNdg‹dËé)L12/19/91°dONLNdpËÙ](6Last reviewed:°dONLNdËdÙÇ)L2/6/92°dONLNdÜ ∫((6WI’d like to know more about that PatStretch field inside a GrafPort or CGrafPort. If I °dONLNd›∫ ⁄((ÿstuff a°dONLNd k(46Dvalues in PatStretch(4) then nothing happens; prints look the same, °dONLNd) k⁄(4âeven using a standard°dONLNd?$(@66bottleneck. Please tell me how I can get this to work.°dONLNdv$0** ___°dONLNdz<H*6PatStretch only works with values of 2 or 3. With any °dONLNd∞<H⁄(d9*other value, it defaults to no stretching.°dONLNd€HTfl(p6(The “2” case was created because of the °dONLNdHflT⁄)«1ImageWriter (72->144 dpi) situation. The “3” case°dONLNd5T`^(|6?was added to support the ImageWriter LQ and the AppleFax modem.°dONLNdulxÍ**So why wasn’t a “4” (72->300 dpi) handler °dONLNdülÍx⁄)“0added for the LaserWriter driver? Good question.°dONLNd–xÑN(†6@Somehow or other it was decided that pattern stretching for the °dONLNdxNÑ⁄(†lLaserWriter driver would be°dONLNd,Ñê⁄(¨6*done completely by the driver itself. The °dONLNdVÑ⁄ê⁄)¬6LaserWriter driver actually does pattern stretching by°dONLNdçêú\(∏6Dusing a pattern 4 times as large, rather than 4.17. In other words, °dONLNd—ê\ú⁄(∏zit really scales the 72 dpi ◊4◊˘
  6060. (Ï612)
  6061.  of 21(ÏñBasic QuickDraw Q&Asˇ8◊#ˇ ˇˇˇˇ#◊ 
  6062. IR,Times
  6063. .+Z-Developer Support Center(-Ê October 1992 /X/
  6064. °dONLNd<)Ä(EZpattern to 288 °dONLNdÄ)˛)DMdpi rather than 300 dpi. You may want to take a similar approach, since you’d°dONLNd])<5%(QZ.only have to work with whole numbers this way.°dONLNdåA<Mw*ASo, if you want to do 4-times pattern stretching, you must scale °dONLNdÕAwM˛(iïthe pattern yourself. If you°dONLNdÍM<Yß(uZNcopy the original pattern into an area that’s twice as wide and twice as tall °dONLNd8MßY˛(u≈and use that, you°dONLNdJY<eœ(ÅZVshould be all set. You’ll need to use PrGeneral to set the printer to the appropriate °dONLNd†Yœe˛(ÅÌ
  6065. resolution°dONLNd´e<q•(çZPand Copybits to copy the pattern into the object that needs to be filled, using °dONLNd˚e•q˛(ç√the “cookie cutter”°dONLNdq<}∑(ôZapproach to fill the object.°dONLNd,â<ï]*X-Ref:°dONLNd3ï<°ˆ* %Inside Macintosh Volume I, page I-150
  6066. °dONLNdYπ<»Q*'&Where CopyBits looks for memory to use
  6067. °dONLNdÄ»<‘b* Written:°dONLNdâ»à‘¶)L1/3/92°dONLNdê‘<‡Å(¸ZLast reviewed:°dONLNdü‘à‡¨)L1/27/92°dONLNdßÏ<¯4(Z1Where does CopyBits look for the memory it needs?°dONLNdŸ¯<N* ___°dONLNd›<¯*'CopyBits checks the stack to determine °dONLNd¯˛)º7if there is enough stack space for it to copy the whole°dONLNd<<(4(DZ2image, which in some cases may be roughly up to 5 °dONLNdn4(˛)¯*extra rowbytes of special effects per row,°dONLNdô(<4Δ(PZRdepending on what special effects such as dithering or scaling are being used. If °dONLNdÎ(Δ4˛(P‰ there is not°dONLNd¯4<@‚(\Z!enough stack space for the whole °dONLNd4‚@˛)¶8image, CopyBits then tries for half the image, and keeps°dONLNdR@<LV(hZ=halving until it gets down to one row of the image (plus the °dONLNdè@VL˛(ht#room for the special effects rows).°dONLNd≥L<X
  6068. (tZ+If there is not enough stack space for one °dONLNdfiL
  6069. X˛)Œ1row of the image, then CopyBits tries to allocate°dONLNdX<dö(ÄZtemporary memory.°dONLNd"p<|O*4Before allocating temporary memory, CopyBits checks °dONLNdVpO|˛(òm!if the temporary memory traps are°dONLNdx|<à-(§Z3available. (They are available under both System 6 °dONLNd´|-à˛)Ò+MultiFinder and System 7.) If the traps are°dONLNd◊à<î(∞ZDavailable, CopyBits tries to allocate a 256K byte buffer for use as °dONLNdàî˛(∞ùa “fake” stack. (CopyBits°dONLNd5î<†V(ºZused °dONLNd:îV†˛)Tto try for a 64K block, but this has been changed, and it may change again.) If this°dONLNdè†<¨)(»Z4succeeds, then all is well and the image is copied. °dONLNd√†)¨˛)Ì+If the temporary memory traps do not exist,°dONLNdÔ¨<∏r(‘Z=or if CopyBits cannot allocate a 256K buffer, then the image °dONLNd,¨r∏˛(‘êis not copied and CopyBits°dONLNdG∏<ƒa(‡Zreturns.°dONLNdP–<‹π*CopyBits does not check °dONLNdh–π‹˛)}Bin the application heap for free memory, at least not for its work°dONLNd´‹<ËÖ(Zbuffer. For its °dONLNdª‹Ö˲)INwork buffer it will only use the stack, and after that it resorts to temporary°dONLNd
  6070. Ë<Ù¬(Zmemory, if available. There °dONLNd&ˬÙ˛)Ü?are some circumstances that may cause memory allocations in the°dONLNdfÙ<ü(ZJapplication heap, but this memory is not used for CopyBits’s image buffer.°dONLNd± <®*NAlso, please note that the implementation of CopyBits is subject to change in °dONLNdˇ ®˛(4Δfuture versions of°dONLNd    <$v(@Z
  6071. QuickDraw.
  6072. °dONLNd    <<KØ*'2PICTs with PostScript PICT comments and memory use
  6073. °dONLNd    PK<Wb* Written:°dONLNd    YKàW¨)L1/10/92°dONLNd    aW<cÅ(ZLast reviewed:°dONLNd    pWàc¨)L2/17/92°dONLNd    xo<{o(óZ    Why does °dONLNd    Åoo{˛)3Jmy PICT (including dotted lines) use so much memory when drawn in MacDraw,°dONLNd    Ã{<á„(£ZSand even more when drawn in SuperPaint? Do they include PicComments for PostScript?°dONLNd
  6074.  á<ìN* ___ ◊X◊
  6075. *=Basic QuickDraw Q&As(Ï˙13)
  6076.  of 21ˇ&◊#ˇ ˇˇˇˇ#◊ 
  6077. IR,Times
  6078. .+6-Macintosh Technical Notes /4/˘
  6079. °dONLNd)¶*OYour guess that it has to do with PicComments is quite right; both MacDraw and °dONLNdO¶)⁄(Eƒ
  6080. SuperPaint°dONLNdZ)5⁄(Q6'include a PostScript representation of °dONLNdÅ)⁄5⁄)¬0the dotted (dashed) lines and some other graphic°dONLNd≤5Aä(]6operations in the PICT, °dONLNd 5äA⁄)rBtogether with the QuickDraw commands. During printing, this allows°dONLNd
  6081. AMd(i6the LaserWriter °dONLNdAdM⁄)LQdriver to take advantage of specific PostScript capabilities that are unavailable°dONLNdoMYˆ(u6/in QuickDraw, like primitives for dashed lines.°dONLNdüeqã*JOn the other hand, the PostScript representation for dashed lines is much °dONLNdÈeãq⁄(ç©shorter than the°dONLNd˙q}`(ô6?QuickDraw representation, which requires a (long, very long …) °dONLNd9q`}⁄(ô~sequence of “ShortLine”°dONLNdQ}âõ(•6opcodes. So, another piece °dONLNdl}õâ⁄)ÉBof explanation for the large PICT size basically is that QuickDraw°dONLNdØâïW(±6Edoes not have facilities to describe dotted lines in an economic way.°dONLNdı°≠∂*YSuperPaint also includes a copy of a proprietary dictionary, which adds substantially to °dONLNdN°∂≠⁄(…‘the size°dONLNdW≠πy(’6Gof a PICT. On the other hand, the code that resides in that dictionary °dONLNdû≠yπ⁄(’ómakes the picture’s°dONLNd≤π≈(·68PostScript representation that much better. Ultimately, °dONLNdÍπ≈⁄(·9"WYSIWYG is the goal, and sometimes°dONLNd
  6082. ≈—z(Ì6Pit takes a little extra code to make that happen. (Incidentally, the PostScript °dONLNd]≈z—⁄(Ìòdictionary contained°dONLNdr—›r(˘6Fin pictures created by older versions of SuperPaint makes assumptions °dONLNd∏—r›⁄(˘êabout the contents of°dONLNdŒ›È(6.the LaserPrep file which are not true for the °dONLNd¸›È⁄)Î*recent versions of the LaserWriter driver.°dONLNd'Èıe(6FDocuments containing such pictures will not print correctly any more.)°dONLNdn
  6083. a*DTo determine the primitives that define other nonstandard QuickDraw °dONLNd≤a
  6084. ⁄()objects found in drawing°dONLNdÀ
  6085. #(562applications, you can use MPW’s DeRez function or °dONLNd˝
  6086. #⁄(5A%a third-party utility such as Palomar°dONLNd#%
  6087. (A60Software’s PICT Detective on the resource PICT. °dONLNdS
  6088. %⁄)ı)These tools will provide the opcodes that°dONLNd}%1g(M6define the PICT.
  6089. °dONLNdéIXû*'8Inside Macintosh Vol. V PICT opcode size should be fixed
  6090. °dONLNd«Xd>* Written:°dONLNd–Xddà)L1/22/92°dONLNdÿdp](å6Last reviewed:°dONLNdÁddpà)L2/28/92°dONLNdÔ|ài(§6EThe definition of PICT version 2 on pages 92-105 of Inside Macintosh °dONLNd4|ià⁄(§áVolume V says that the°dONLNdKàî¬(∞6#data size of the opcodes $001A and °dONLNdnà¬î⁄)™9$001B is variable, but also that the data is an RGBColor.°dONLNd®î†
  6091. (º61This is confusing, since the size of an RGBColor °dONLNdŸî
  6092. †⁄)ı(is fixed at six bytes. How can these two°dONLNd†¨ı(»6.opcodes vary in the amount of associated data?°dONLNd1¨∏** ___°dONLNd5ƒ–¥*ZSeems like you’ve run into a cut/paste problem. All the opcodes that refer to table 4 are °dONLNd胥–⁄(Ï“new for°dONLNdó–‹((¯64Color QuickDraw. Also, most of them are variable in °dONLNdÀ–(‹⁄(¯F"length, so the author simply had a°dONLNdÓ‹ËÂ(6(standard notation for anything that was °dONLNd    ‹ÂË⁄)Õ.explained further in table 4 (page V-103). The°dONLNd    EËÙ´(6information contained in table °dONLNd    dË´Ù⁄)ì?4 is, in fact, accurate. The size information of several of the°dONLNd    §Ùú(6Ropcodes listed is not variable even though the preceding pages told you they were.°dONLNd    ˜ *9All you gotta do is believe table 4 and you will be fine.
  6093. °dONLNd
  6094. 10?g*'1Code for filling an area fully bounded by polygon
  6095. °dONLNd
  6096. c?K>* Written:°dONLNd
  6097. l?dKà)L2/21/92°dONLNd
  6098. tKW](s6Last reviewed:°dONLNd
  6099. ÉKdWà)L6/11/92°dONLNd
  6100. ãcoÃ(ã6]Currently, when a polygon is filled, an even-odd rule is applied to determine which areas of °dONLNd
  6101. ËcÃo⁄(ãÍthe°dONLNd
  6102. Ïo{e(ó6Hpolygon are to be filled. For our application, we also need to fill all °dONLNd 4oe{⁄(óÉthe areas of the defined°dONLNd M{á+(£6;polygon. Is there a relatively easy way to accomplish this?°dONLNd âáì** ___ ◊4◊˘
  6103. *=14)
  6104.  of 21(ÏñBasic QuickDraw Q&Asˇ∫◊#ˇ ˇˇˇˇ#◊ 
  6105. IR,Times
  6106. .+Z-Developer Support Center(-Ê October 1992 /X/
  6107. °dONLNd<)≥(EZThere are many different °dONLNd≥)˛)wAways to fill polygons, as you may know. If you do not want to use°dONLNd[)<52(QZ3QuickDraw’s standard FillPoly routine, you’ll have °dONLNdé)25˛)ˆ(to create your own. The following sample°dONLNd∑5<AÛ(]Zaillustrates one technique that might be used to fill the area fully bounded by a polygon. It can °dONLNd5ÛA˛(]be°dONLNdA<Mù(iZKdropped right into the traffic light sample (sample.p) that ships with MPW °dONLNdfAùM˛(iªas a replacement for°dONLNd{M<Yø(uZOits DrawWindow procedure. The green star is drawn using FillPoly and the black °dONLNd MøY˛(u›
  6108. star is drawn°dONLNdÿY<ed(ÅZ=using my filling technique that uses an offscreen bitmap and °dONLNdYde˛(ÅÇ calcMask to fill in the poly the°dONLNd6e<qì(çZdesired way, then °dONLNdHeìq˛)WJCopyBits to transfer it to the onscreen port. The drawbacks of this method°dONLNdìq<}W(ôZBare that it is not as fast as writing a specialized poly routine; °dONLNd’qW}˛(ôu&the benefits are that it’s small, fast°dONLNd¸}<âö(•ZHenough for most operations, and can be used for more than just polygons.,
  6109. Courier
  6110.     °dONLNdEï<†i*    {$S Main}°dONLNdOü<™*
  6111. (PROCEDURE DrawWindow(window: WindowPtr);°dONLNdx≥<æÕ*var        MyPoly:PolyHandle;°dONLNdñΩ<»π*
  6112.         MyRgn :RgnHandle;°dONLNd∞«<“◊*
  6113.         OffPort,OnPort:GrafPtr;°dONLNd–€<ÊO*7    Function    CreateOffport(VAR newOffscreen:grafPtr;°dONLNd    Â<Ø*
  6114. inBounds:Rect):Boolean;°dONLNd!˘<*$    var    SavePort,NewPort:Grafptr;°dONLNdF
  6115. <i*        begin°dONLNdP<"æ*
  6116.         GetPort(SavePort);°dONLNdk!<,;*
  6117. 3        NewPort:=GrafPtr(NewPtr(sizeof(grafport)));°dONLNdü+<6ı*
  6118. %        If MemError<>noErr then Begin°dONLNd≈5<@·*
  6119. !            CreateOffport:=false;°dONLNdÁ?<J‹*
  6120.              EXIT(CreateOffport);°dONLNdI<Tx*
  6121.         END;°dONLNd]<hæ*        OpenPort(newPort);°dONLNd8g<r“*
  6122.         With newPort^ do begin°dONLNdWq<|‹*
  6123.              portRect :=Inbounds;°dONLNdx{<Ü˙*
  6124. &            RectRgn(ClipRgn,inBounds);°dONLNdüÖ<ê˙*
  6125. &            RectRgn(visRgn, inBounds);°dONLNdΔè<öx*
  6126.         End;°dONLNd€£<Æˇ*'        With newPort^.PortBits DO BEGIN°dONLNd≠<∏Õ*
  6127.             Bounds:=Inbounds;°dONLNd!∑<¬ï*
  6128. E            rowBytes:= ((inBounds.right-inBounds.Left+15) DIV 16) *2;°dONLNdg¡<Ã˙*
  6129. &            baseAddr:= NewPtr(rowBytes°dONLNdèÀ<÷ï*
  6130. E                            * LONGINT(inBounds.Bottom-inBounds.Top));°dONLNd’’<‡x*
  6131.         End;°dONLNd‚fl<Í˙*
  6132. &        If MemError <>noErr THEN BEGIN°dONLNd    È<Ù“*
  6133.             SetPort(SavePort);°dONLNd(Û<˛◊*
  6134.             ClosePort(newPort);°dONLNdH˝<*
  6135. $            DisposPtr(ptr(newPort));°dONLNdm<·*
  6136. !            CreateOffport:=false;°dONLNdè<}*
  6137.  
  6138.           END°dONLNdù<&õ*
  6139.         ELSE  BEGIN°dONLNd±%<0‹*
  6140.              EraseRect(inBounds);°dONLNd“/<:Î*
  6141. #            newOffscreen :=newPort;°dONLNdˆ9<D“*
  6142.             setPort(SavePort);°dONLNdC<N‹*
  6143.              CreateOffPort:=true;°dONLNd6M<Xx*
  6144.         end;°dONLNdCW<bd*
  6145.     end;°dONLNdPk<v@*4    Procedure    KillOffPort(oldOffscreen :GrafPtr);°dONLNdÖu<Äi*
  6146.         Begin°dONLNdè<ä‹*
  6147.          ClosePort(oldOffscreen);°dONLNd∞â<î;*
  6148. 3        DisposPtr(OldOffscreen^.portBits.baseAddr);°dONLNd‰ì<ûı*
  6149. %        DisposPtr(ptr(OldOffScreen));°dONLNd    
  6150. ù<®d*
  6151.     End; ◊X◊
  6152. *(Basic QuickDraw Q&As(Ï˙15)
  6153.  of 21ˇ fi◊#ˇ ˇˇˇˇ#◊ 
  6154. IR,Times
  6155. .+6-Macintosh Technical Notes /4/˘,
  6156. Courier
  6157.     °dONLNd'21*!BEGIN°dONLNd1<è*
  6158. K    If NOT (CreateOffPort(offPort,window^.portRect)) THEN Exit(DrawWindow);°dONLNdR;Fä*
  6159. J    If NOT (CreateOffPort(onPort,window^.portRect)) THEN Exit(DrawWindow);°dONLNd°OZ|*    SetPort(window);°dONLNd∂cnr*    MyRgn:=NewRgn;°dONLNd…mxT*
  6160.     OpenRgn;°dONLNd÷wÇÜ*
  6161.         MoveTo(10,25);°dONLNdÌÅåÜ*
  6162.         Lineto(70,25);°dONLNdãñÜ*
  6163.         Lineto(15,70);°dONLNdï†Ü*
  6164.         Lineto(40,10);°dONLNd2ü™Ü*
  6165.         Lineto(65,70);°dONLNdI©¥Ü*
  6166.         Lineto(10,25);°dONLNd`≥æ|*
  6167.     CloseRgn(MyRgn);°dONLNdu«“Å*    MyPoly:=OpenPoly;°dONLNdã—‹Ü*
  6168.         MoveTo(10,25);°dONLNd¢€ÊÜ*
  6169.         Lineto(70,25);°dONLNdπÂÜ*
  6170.         Lineto(15,70);°dONLNd–Ô˙Ü*
  6171.         Lineto(40,10);°dONLNdÁ˘Ü*
  6172.         Lineto(65,70);°dONLNd˛Ü*
  6173.         Lineto(10,25);°dONLNd
  6174. ^*
  6175.     ClosePoly;°dONLNd$"©*
  6176.     OffsetPoly(MyPoly,0,100);°dONLNdB+6Å*    SetPort(OffPort);°dONLNdX5@Ü*
  6177.     FramePoly(MyPoly);°dONLNdo?JÂ*
  6178. )    { Now "Fill the poly" the right way }°dONLNdôITv*
  6179. F    CalcMask(    Offport^.portBits.BaseAddr,OnPort^.portBits.BaseAddr,°dONLNd‡S^v*
  6180. F                OffPort^.portBits.RowBytes, OnPort^.portBits.RowBytes,°dONLNd']hN*
  6181. >                OffPort^.portRect.bottom-OnPort^.portRect.Top,°dONLNdfgr*
  6182. 2                OffPort^.portBits.RowBytes DIV 2);°dONLNdôq||*
  6183.     SetPort(OnPort);°dONLNdÆ{Ü|*
  6184.     SetPort(Window);°dONLNdƒèö|*    If gStopped then°dONLNdŸô§0*
  6185. 8        CopyBits(    OnPort^.portBits, Window^.portBits,°dONLNd£Æq*
  6186. E                    OnPort^.portRect, Window^.portRect, srcCopy, NIL)°dONLNdX≠∏@*
  6187.     ELSE°dONLNda∑¬5*
  6188. 9        CopyBits(    OffPort^.portBits, Window^.portBits,°dONLNdõ¡Ã{*
  6189. G                    OffPort^.portRect, Window^.portRect, srcCopy, NIL);°dONLNd„’‡|*    IF gStopped THEN°dONLNd¯flÍO*
  6190.       begin°dONLNdÈÙÆ*
  6191.         ForeColor(greenColor);°dONLNd#Û˛ê*
  6192.         FrameRgn(MyRgn);°dONLNd<˝E*
  6193.           end°dONLNdF@*
  6194.     ELSE°dONLNdOO*
  6195.       begin°dONLNd[&Æ*
  6196.         ForeColor(greenColor);°dONLNdz%0ê*
  6197.         PaintRgn(MyRgn);°dONLNdì/:J*
  6198.  
  6199.       end;°dONLNdû9Dö*
  6200.     ForeColor(blackColor);°dONLNdπCNÜ*
  6201.     DisposeRgn(MyRgn);°dONLNd–MXÅ*
  6202.     KillPoly(MyPoly);°dONLNdÊWbï*
  6203.     KillOffPort(Offport);°dONLNdalê*
  6204.     KillOffPort(OnPort);°dONLNdkvm*
  6205. END; {DrawWindow}
  6206. °dONLNd+çú£*&7Use crsrNew flag to unobscure cursor without mouse move
  6207. °dONLNdcú®>* Written:°dONLNdlúd®Ç)L3/3/92 ◊4◊˘
  6208. (Ï616)
  6209.  of 21(ÏñBasic QuickDraw Q&AsˇÍ◊#ˇ ˇˇˇˇ#◊ 
  6210. IR,Times
  6211. .+Z-Developer Support Center(-Ê October 1992 /X/
  6212. °dONLNd<)Å(EZLast reviewed:°dONLNdà)¨)L6/11/92°dONLNd5<AU(]Z4The Macintosh QuickDraw routine ObscureCursor hides °dONLNdK5UA˛(]s"the cursor until the next time the°dONLNdnA<MÓ(iZXmouse is moved but isn’t affected by HideCursor or ShowCursor. Our application needs to °dONLNdΔAÓM˛(i use°dONLNd M<YÓ(uZZObscureCursor while the user is typing but needs the cursor to be visible after no typing °dONLNd$MÓY˛(u has°dONLNd(Y<e(ÅZ'occurred for a short period. How do we °dONLNdOYe˛)»0“undo” ObscureCursor, since we can’t rely on the°dONLNdÄe<qØ(çZuser moving the mouse?°dONLNdóq<}N* ___°dONLNdõâ<ï˘*%The only way to unobscure the cursor °dONLNd¿â˘ï˛)Ω2is to convince the system that the mouse has moved°dONLNdÛï<°/(ΩZ5again. There is no real good way to do this via tool °dONLNd(ï/°˛)Û,calls, so you are going to have to do it the°dONLNdU°<≠T(…Zhard °dONLNdZ°T≠˛)Uway and simply update the low-memory cursor information to tell the system the cursor°dONLNd∞≠<πz(’ZBmoved (even though you do not need to update the actual position).°dONLNdÛ≈<—Œ*OTo tell the system the cursor has changed location, you simply set the crsrNew °dONLNdB≈Œ—˛(ÌÏ
  6213. flag to 1;°dONLNdM—<›_(˘Z9crsrNew is a byte located at $08CE. When the system sees °dONLNdÜ—_›˛(˘}!this byte is 1 it will assume the°dONLNd®›<Èè(ZGcursor has moved, unobscure it, redraw at the appropriate place (where °dONLNdÔ›èÈ˛(≠it was all along...) and°dONLNdÈ<ı˛(Z]reset crsrNew waiting for the mouse to move again, as in the following C and Pascal examples:,
  6214. Courier
  6215.     °dONLNdf< ™*/* the C version... */°dONLNd} <Õ*
  6216. void UnObscureCursor ( void )°dONLNdõ< A*
  6217. {°dONLNdù<*™*
  6218.    *(char *)0x8CE = 1;°dONLNd¥)<4A*
  6219. }°dONLNd∂=<H¥*(* the pascal version *)°dONLNdœG<Ræ*
  6220. Procedure UnObscureCursor;°dONLNdÍ[<fU*begin°dONLNde<pñ*
  6221.    ptr($08CE)^:=1;°dONLNdo<zP*
  6222. end;
  6223. °dONLNdÖ<ëW*;This will do what you want in a short, easy-to-use package.
  6224. °dONLNdD©<∏.*'!Macintosh QuickDraw region quirks
  6225. °dONLNdf∏<ƒb* Written:°dONLNdo∏àƒ¶)L1/1/90°dONLNdvƒ<–Å(ÏZLast reviewed:°dONLNdÖƒà–≤)L11/21/90°dONLNdé‹<ËP(ZI’m °dONLNdí‹P˲)Sworking with regions, and I’m having problems with Macintosh QuickDraw trashing the°dONLNdÊË<ÙU(Z8heap and crashing, even though my regions are under 32K.°dONLNdÙ<N* ___°dONLNd# <π*There are some quirks in °dONLNd< π˙)}<the current version of QuickDraw. Here are some the commonly°dONLNdx ˙˛(4-°dONLNdy<$ß(@Zencountered problems:°dONLNdè0<<æ*1. When doing operations °dONLNd®0æ<˛)Ç;which use more than one region, sduch as UnionRgn, DiffRgn,°dONLNd‰<<H\(dZ7XorRgn, or SectRgn, the sum of the sizes of the source °dONLNd<\HÖ(dzregions °dONLNd#<ÖHfl))must be less than°dONLNd4<flH˛)Z 32K,°dONLNd:H<T(pZ/regardless of the size of the resulting region.°dONLNdj`<ls*D2. FrameRgn will fail if it tries to frame a region bigger than 16K.°dONLNdØx<Ñÿ*#3. If CloseRgn fails, the internal °dONLNd“xÿÑ˛)ú>region data is already corrupt; there is nothing you can do to°dONLNdÑ<ê›(¨Z]recover. CloseRgn will also fail if there isn’t at least a 32K block of free space available.°dONLNdoú<®≈*Here are some workarounds: ◊X◊
  6226. *(Basic QuickDraw Q&As(Ï˙17)
  6227.  of 21ˇ
  6228. ◊#ˇ ˇˇˇˇ#◊ 
  6229. IR,Times
  6230. .+6-Macintosh Technical Notes /4/˘
  6231. °dONLNd)5É*$1. Keep regions small °dONLNd)É5⁄)kFand not too complex. Keep track of the sizes of all regions so you can°dONLNd]5Ak(]6Icheck the SUM of the sizes before calling a routine that has a 32K limit.°dONLNdßMY¨*V2. Keep 32K free, or allocate a 32K block and release it just before calling CloseRgn.°dONLNd˛eq”*[Apple is working on these problems and expects to fix them in future versions of QuickDraw.
  6232. °dONLNdZâòV*',How to get Macintosh QuickDraw arc endpoints
  6233. °dONLNdáò§>* Written:°dONLNdêòd§Ç)L1/1/90°dONLNdó§∞](Ã6Last reviewed:°dONLNd¶§d∞é)L11/21/90°dONLNdغ»Í(‰6*Is there a way to obtain the endpoints of °dONLNdŸºÍ»⁄)“+an arc drawn by the Macintosh QuickDraw arc°dONLNd»‘fl(6(routines, such as FrameArc and PaintArc?°dONLNd.‘‡** ___°dONLNd2ϯó*OGiven a rectangle R which frames the arc you wish to draw, convert your angles °dONLNdÅÏó¯⁄(µto an absolute°dONLNdê¯ö( 6Qcoordinate system, where three o’clock is 0 degrees and 12 o’clock is 90 degrees.°dONLNd‚E*    Now, let:,
  6234. Courier
  6235.     °dONLNdÏ(3÷*&    x = .5 (+ or -) (R.right - R.left)°dONLNd2=÷*
  6236. &    y = .5 (+ or -) (R.bottom - R.top)
  6237. °dONLNd:HTÏ*-The endpoint of the curve will be defined by:
  6238.     °dONLNdh`k—*%    EndPoint.h = x (+ or -) cos(ang);°dONLNdéju—*
  6239. %    EndPoint.v = y (+ or -) sin(ang);
  6240. °dONLNd¥ÄåŸ*+h & v are relative to center of rectangle R°dONLNd‡ò§±*This calculates only the upper °dONLNdˇò±§⁄)ô;endpoint of the arc, but you can easily calculate the other°dONLNd;§∞ø(Ã6 endpoint using the same formula °dONLNd[§ø∞⁄)ß9by calculating the absolute angle for the start point and°dONLNdï∞ºô(ÿ6applying the same formula.°dONLNd∞»‘u*KHere is a subroutine which illustrates the algorithm, in LightSpeed Pascal:
  6241.     °dONLNd¸‡Î]*A{ DrawCurve: draw an arc from 0 degrees until the point defined }°dONLNd>Íı&*
  6242. 6{ by 'angle'. At that point draw a 4 by 4 crosshair. }°dONLNd粠   *4procedure DrawCurve (frame : Rect; angle : integer);°dONLNd¬'*var°dONLNdΔ'm*
  6243.   x, y : integer;°dONLNdÿ&1|*
  6244.   xr, yr : extended;°dONLNdÌ0;m*
  6245.   rad : extended;°dONLNdˇDO1*begin°dONLNdXcÆ*  { Convert angle to radians }°dONLNd$bm÷*
  6246. &  rad := (90 - angle) / 180 * 3.14159;°dONLNdKvÅ|*  { Find end point }°dONLNd`Äã*
  6247. 2  xr := (frame.right - frame.left) * cos(rad) / 2;°dONLNdìäï*
  6248. 2  yr := (frame.bottom - frame.top) * sin(rad) / 2;°dONLNdΔîü0*
  6249. 8  x := (frame.right + frame.left) / 2 + Num2Integer(xr);°dONLNdˇû©0*
  6250. 8  y := (frame.bottom + frame.top) / 2 + Num2Integer(yr); ◊4◊˘
  6251. *'18)
  6252.  of 21(ÏñBasic QuickDraw Q&AsˇX◊#ˇ ˇˇˇˇ#◊ 
  6253. IR,Times
  6254. .+Z-Developer Support Center(-Ê October 1992 /X/,
  6255. Courier
  6256.     °dONLNd'<2†(NZ  { Draw crosshair }°dONLNd1<<õ*
  6257.   MoveTo(x - 4, y);°dONLNd);<Fõ*
  6258.   LineTo(x + 4, y);°dONLNd=E<Põ*
  6259.   MoveTo(x, y - 4);°dONLNdQO<Zõ*
  6260.   LineTo(x, y + 4);°dONLNdec<nÇ*  { Draw arc }°dONLNdtm<x»*
  6261.   FrameArc(frame, 0, angle);°dONLNdëw<ÇP*
  6262. end;
  6263. °dONLNdñô<®c*&*Macintosh CopyBits no longer limited to 3K
  6264. °dONLNd¡®<¥b* Written:°dONLNd ®à¥¶)L5/3/89°dONLNd—¥<¿Å(‹ZLast reviewed:°dONLNd‡¥à¿≤)L11/21/90°dONLNdÈÃ<ÿÙ(ÙZ_Inside Macintosh Volume I (page 188) says there is a 3K limit for CopyBits. Is this still true?°dONLNdIÿ<‰N* ___°dONLNdM<¸Ü*HThe CopyBits limit is obsolete; there is no longer a 3K limit. The limit°dONLNdñ¸<Ü* Bdepends on the amount of RAM in your Macintosh. CopyBits tries to °dONLNdÿ¸Ü˛($§use the stack to do all of°dONLNdÛ<é(0ZHthe copying. In most cases CopyBits is able to copy entire screen shots °dONLNd;é˛(0¨at one time. You might°dONLNdR< °(<Zrun into problems if °dONLNdg° ˛)eByou don’t have enough stack to hold two times the rowBytes of your°dONLNd™ <,≥(HZPsource, but even in this case CopyBits will attempt to find the memory it needs.°dONLNd˚8<D]*X-Ref:°dONLNdD<PÓ* #Inside Macintosh Volume I, page 188
  6265. °dONLNd&h<w‡*';Why grafPort’s clipRgn should be changed before OpenPicture
  6266. °dONLNdbw<Éb* Written:°dONLNdkwàɨ)L11/1/90°dONLNdsÉ<èÅ(´ZLast reviewed:°dONLNdÇÉàè≤)L12/19/90°dONLNdãõ<ßO(√ZOn °dONLNdéõO߲)Qpage 189 of Inside Macintosh, Volume I, in the QuickDraw chapter’s description of°dONLNd‡ß<≥Ù(œZ&OpenPicture, is the following warning:°dONLNdø<À¶*P“A grafPort's clipRgn is initialized to an arbitrarily large region. You should °dONLNdWø¶À˛(Áƒalways change the°dONLNdiÀ<◊Ó(ÛZYclipRgn to a smaller region before calling OpenPicture, or no drawing may occur when you °dONLNd¬ÀÓ◊˛(Û call°dONLNd«◊<„Ä(ˇZ
  6267. DrawPicture.”°dONLNd’Ô<˚ı*(The “arbitrarily large” clipping region °dONLNd˝Ôı˚˛)π4rectangle is set to -32767,- 32767,32767,32767 (top,°dONLNd2˚<ˆ(#Z)left, bottom, right) for new ports. This °dONLNd[˚ˆ˛)∫;is the largest rectangle possible. If this is not a "valid"°dONLNdó<í(/Zclipping rectangle °dONLNd™í˛)VOfor pictures, what is? Is there some specific limit to the size of the clipping°dONLNd˙<Ø(;ZPrectangle? Does it depend on either available memory or the size of the picture?°dONLNdK<+N* ___°dONLNdO7<Cÿ*ZInside Macintosh ’s warning is based on truth but it’s incomplete. It didn’t actually say °dONLNd©7ÿC˛(_ˆ    that this°dONLNd≥C<Oa(kZCrectangle is invalid as a clipping region, because this is in fact °dONLNdˆCaO˛(k"a perfectly valid clipping region.°dONLNdO<[¨(wZFBut, you could run into problems if you use this as a clipping region °dONLNd_O¨[˛(w when creating a°dONLNdo[<g"(ÉZ2QuickDraw picture. It’s not a matter of available °dONLNd°["g˛)Ê.memory or size; it’s a simple matter of 16-bit°dONLNd–g<s¯(èZ&signed integer overflow and underflow.°dONLNd˜<ã]*When °dONLNd¸]ã˛)!Syou open a picture, the current clip region is recorded in the picture (this wasn’t°dONLNdPã<óù(≥ZEnecessarily true in some early versions of QuickDraw). When you draw °dONLNdïãùó˛(≥ªthe resulting picture°dONLNd´ó<£ñ(øZusing the picture’s °dONLNdøóñ£˛)ZJpicFrame as the destination rectangle, there won’t be any problems. But if ◊X◊
  6268. (ÏZBasic QuickDraw Q&As(Ï˙19)
  6269.  of 21ˇ.◊#ˇ ˇˇˇˇ#◊ 
  6270. IR,Times
  6271. .+6-Macintosh Technical Notes /4/˘
  6272. °dONLNd)A*Ayou use a destination rectangle that’s larger than the picFrame, °dONLNdAA)⁄(E_QuickDraw scales everything in°dONLNd`)5L(Q6 the picture °dONLNdl)L5⁄)4Uproportionately, including the clip region. If you allowed the default clip region to°dONLNd¬5A(]68be recorded into the picture, then its rgnBBox, already °dONLNd˙5A⁄(]:'as large as possible, will be made even°dONLNd"AMA(i6:larger. That means that the -32767 coordinates might wrap °dONLNd\AAM⁄(i_around to the positive number°dONLNdzMY§(u6Qrange, and the 32767 coordinates might wrap around to the negative number range. °dONLNdÀM§Y⁄(u¬ This leaves°dONLNd◊Ye&(Å69you with an empty clip region. Nothing at all gets drawn °dONLNdY&e⁄(ÅD&when the current port’s clip region is°dONLNd7eq9(ç6empty.°dONLNd>}âŸ*(If the destination rectangle is smaller °dONLNdf}Ÿâ⁄)¡/than the picture’s picFrame, you won’t have any°dONLNdñâï´(±6Uproblems because the default clip region will be made smaller, and that’s no problem.°dONLNdϰ≠∫*UThis is why Inside Macintosh suggests that you make the clip region smaller than the °dONLNdA°∫≠⁄(…ÿdefault°dONLNdI≠πµ(’6Sclip region before opening a picture. By doing this, you’re almost guaranteed that °dONLNdú≠µπ⁄(’”the clip°dONLNd•π≈¨(·6region won’t get scaled to the °dONLNdƒπ¨≈⁄)î=point that it turns inside out. What size should you make it?°dONLNd≈—§(Ì6SSmall enough so that the risk of the clip region’s coordinates being scaled out of °dONLNdU≈§—⁄(̬    QuickDraw°dONLNd_—›ê(˘6Scoordinate space is minimal. I usually just set the clip region to the picFrame of °dONLNd≤—ê›⁄(˘Æthe picture. It’s°dONLNdƒ›Èô(6hard to go wrong this way.
  6273. °dONLNdflY*'+Macintosh CalcMask and CopyMask code sample
  6274. °dONLNd >* Written:°dONLNddà)L2/27/92°dONLNd(](D6Last reviewed:°dONLNd+d(à)L5/21/92°dONLNd34@–(\6(I can’t get the black-and-white version °dONLNd[4–@⁄)∏5of my lasso-type tool to work correctly with CalcMask°dONLNdë@Lµ(h6Pand CopyMask. With CalcCMask it seems to work fine. What could I be doing wrong?°dONLNd‚LX** ___°dONLNdÊdpO*>CalcMask and CalcCMask are similar in that they both generate °dONLNd$dOp⁄(åma 1-bit mask given a source°dONLNd@p|(ò6-bitmap. With CalcCMask, though, a pixMap can °dONLNdmp|⁄)*be used in place of the source bitmap; the°dONLNdò|à‡(§6(seedRGB determines which color sets the °dONLNd¿|‡à⁄)»2bits in the mask image. An easy mistake to make is°dONLNdÛàî(∞67to forget that CalcCMask accepts a pointer to a bitmap °dONLNd*àî⁄(∞7'data structure while CalcMask expects a°dONLNdRî†{(º6pointer to the actual °dONLNdhî{†⁄)cBbit image. And unlike CalcCMask, which uses bounding Rects for the°dONLNd´†¨—(»6Pimage’s dimensions, CalcMask uses the bitmap’s rowBytes and pixel image offsets °dONLNd˚†—¨⁄(»Ôto°dONLNd˛¨∏®(‘6Udetermine the bounding Rects for the image. A typical call to these routines would be,
  6275. Courier
  6276.     °dONLNdTƒœê*    BitMap source, mask;°dONLNdmŒŸN*
  6277. >    CalcMask (source.baseAddr, mask.baseAddr, source.rowBytes,°dONLNd≠ÿ„l*
  6278. D              mask.rowBytes, source.bounds.bottom-source.bounds.top,°dONLNdÛ‚̬*
  6279. "              source.rowBytes>>1);°dONLNd    Ï˜b*
  6280. B    CalcCMask (&source, &mask, &(*source).bounds, &(*mask).bounds,°dONLNd    ZˆΩ*
  6281. !               &seedRGB, nil, 0);
  6282. °dONLNd    | 
  6283. *3One last thing to note when using CalcMask is that °dONLNd    Ø 
  6284. ⁄)Ú*the width of the image is in words and not°dONLNd    ⁄$(@64bytes. To learn more about these routines, see page °dONLNd
  6285. $⁄)˛$24 of Inside Macintosh Volume IV and°dONLNd
  6286. 3$0¨(L6Rpage 72 of Inside Macintosh Volume V. Also, the Developer CD Series disc contains °dONLNd
  6287. Ö$¨0⁄(L     a sample,°dONLNd
  6288. è0<X(X6>CalcCMask&CalcMask, that shows how to use both these routines.
  6289. °dONLNd
  6290. ŒTcn*'-Macintosh QuickDraw LineTo bug and workaround
  6291. °dONLNd
  6292. ¸co>* Written:°dONLNd cdoà)L4/23/92°dONLNd
  6293. o{](ó6Last reviewed:°dONLNd od{à)L7/13/92°dONLNd $áì(Ø61Our zooming function crashes into flames when we °dONLNd Uáì⁄)ˆ*pass valid coordinate values to LineTo, as°dONLNd Äìüê(ª6in the following example: ◊4◊˘
  6294. *120)
  6295.  of 21(ÏñBasic QuickDraw Q&AsˇN◊#ˇ ˇˇˇˇ#◊ 
  6296. IR,Times
  6297. .+Z-Developer Support Center(-Ê October 1992 /X/,
  6298. Courier
  6299.     °dONLNd<(†(DZ    SetPort(myPort);°dONLNd'<2™*
  6300.     MoveTo(154,31619);°dONLNd,1<<*
  6301. +    LineTo(74, -31742); (* You are dead! *)
  6302. °dONLNdXG<S)*1What can we do to avoid LineTo crashes like this?°dONLNdäS<_N* ___°dONLNdék<wΔ*The QuickDraw Engineering °dONLNd®kΔw˛)ä=group is aware of the problem you described. The bug probably°dONLNdÊw<É(üZ.is going to be fixed in the next release that °dONLNdwɲ)…3includes bug fixes. Given that waiting for a system°dONLNdHÉ<èC(´Z6solution may demand more patience than is reasonable, °dONLNd~ÉCè˛(´a%you may want to consider including in°dONLNd§è<õÖ(∑ZCyour software some form of workaround that will prevent your users °dONLNdÁèÖõ˛(∑£from crashing every time°dONLNdõ<ßR(√Z;an operation takes the software to the limits of QuickDraw.°dONLNd<≥<øŸ*XOne way to approach this problem is to replace the lineProc bottleneck. All you need to °dONLNdî≥Ÿø˛(€˜do is to°dONLNdùø<Àî(ÁZcheck the distance °dONLNd∞øîÀ˛)XJbetween the current pen position and the line’s end, and when the distance°dONLNd˚À<◊Ù(ÛZVbecomes too big (let’s say more than 32000) your procedure will call StdLine a couple °dONLNdQÀÙ◊˛(Ûof°dONLNdT◊<„Á(ˇZ×, splitting the operation in two.°dONLNd{Ô<˚¬*Replacing the bottlenecks is °dONLNdòÔ¬˚˛)Ü@a very straightforward operation (which you are probably already°dONLNdŸ˚<—(#Z using) and in most of the cases °dONLNd˘˚—˛)ïAwill only result in another level of indirection into StdLine but°dONLNd;<œ(/Zthat will prevent your program °dONLNdZœ˛)ì=from calling QuickDraw with parameters that are guaranteed to°dONLNdò<Ä(;Zcause crashes.
  6303. °dONLNdß7<F*'QuickDraw globals at INIT time"VW
  6304. °dONLNdΔF<Rb* Written:°dONLNdœFàR¶)L6/1/92"eW °dONLNd÷R<^Å(zZLast reviewed:°dONLNdÂRà^¨)L9/15/92"qW "}W °dONLNdÌj<vc(íZ@If I call InitGraf before I reference CurrentA5, will CurrentA5 °dONLNd-jcv˛(íÅbe valid and can the QuickDraw"âW °dONLNdLv<Ç[(ûZ;globals be referenced off it? The screenBits bounds values °dONLNdáv[Dz(ûyseem screwy on some machines."ïW °dONLNd•Ç<éw(™Z@Does the problem lie with CurrentA5? Should I be referencing A5?"°W °dONLNdÊé<öN* ___"≠W "πW °dONLNdͶ<≤˙*%Here’s the process used by ShowINIT, °dONLNd¶˙≤˛)æ3which is remarkably compatible with system software"≈W °dONLNdC≤<æu(⁄Z<and other INITs (and it had better be, because it’s used by °dONLNd≤uæ˛(⁄ìmore than half the system"—W °dONLNdôæ< °(ÊZextensions available):"›W "ÈW °dONLNd∞÷<‚_*B1. It saves the value in the CurrentA5 global to restore it later."ıW °dONLNdÛ‚<ÓÜ* I2. It points the A5 register at 4 bytes of storage for use by the system."W °dONLNd=Ó<˙R* ;3. It copies the value now in A5 into the CurrentA5 global."
  6305. W °dONLNdy˙<Â* ^4. It calls InitGraf, passing a pointer to the thePort field of a QuickDraw globals structure."W °dONLNdÿ<»* V5. It opens a port and draws as necessary. [This is where all the functionality goes.]"%W °dONLNd/<‚* '6. After it’s done, it closes its port."1W °dONLNdW<*P* >7. It copies the value saved in step (1) into the A5 register."=W °dONLNdñ*<6W* =8. It copies the restored A5 value into the CurrentA5 global."IW "UW °dONLNd‘B<Nà*To summarize, °dONLNd‚BàN˛)LIShowINIT saves the A5, creates and initializes its own A5 world, does its"aW °dONLNd    ,N<Z≤(vZKdrawing, then restores the previous A5 world. For more information on this °dONLNd    wN≤Z˛(v–subject, see the"mW °dONLNd    àZ<f(ÇZ,Macintosh Technical Note “Stand-Alone Code.”"yW  ◊X◊
  6306. *jBasic QuickDraw Q&As(Ï˙21)
  6307.  of 21ˇ◊#ˇ ˇˇˇˇ#◊†Ç 
  6308. /ZÅ#
  6309.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  6310. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  6311. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  6312. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  6313. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  6314.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  6315. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  6316. IR.°dONLNdz<çS(ßZSo Many Bitmaps, So Little Time
  6317. °dONLNd å<õr*Imaging°dONLNd(ågõ˛(∑ÖM.IM.BitMatToRegion
  6318. °dONLNd<ß<≥t(œZ Revised by:°dONLNdHßÑ≥¿)H Rich Collyer°dONLNdUߥ≥˛(œ“
  6319. December 1989°dONLNdc≥<øq(€Z Written by:°dONLNdo≥Ñø¥)H
  6320. Rick Blair°dONLNdz≥Àø˛(€È
  6321. April 1988°dONLNdÖÃ<ÿT(ÙZThis °dONLNdäÃTÿ)%Technical Note discusses the routine ,
  6322. Courier°dONLNdØÀ◊j)¥BitMapToRegion°dONLNdΩÃjÿ˛)b, which converts a bitmap to a°dONLNd‹ÿ<‰Î(ZXregion, and is available in the 32-Bit QuickDraw INIT and from Apple Software Licensing.°dONLNd5‰<Á* Changes since October 1989:°dONLNdP‰Á‡)´2  Added trap definitions for developers using the °dONLNdlj‡˛)˘32-Bit°dONLNdâ<¸í(ZGQuickDraw version of this routine without the correct MPW include file. 'X'°dONLNd—<!á*%GThe following routine is now available to convert a bitmap to a region:
  6323.     °dONLNd-<8r*>FUNCTION BitMapToRegion(region:RgnHandle; bMap:BitMap): OSErr;
  6324. °dONLNdXC<OS*in C:
  6325.     °dONLNd^[<fc*;pascal OSErr BitMapToRegion(RgnHandle region, BitMap bMap);
  6326. °dONLNdöq<}ò*JIf you are using the 32-Bit QuickDraw version of this routine without the °dONLNd‰qò}˛(ô∂correct MPW include°dONLNd¯}<â`(•Z@file, then you need to include one of the following definitions:°dONLNd9ï<°Z*Pascal
  6327.     °dONLNd@≠<∏Å*AFUNCTION BitMapToRegion (region: RgnHandle; bMap: BitMap): OSErr;°dONLNdÇ∑<¬™*
  6328.          INLINE $A8D7;
  6329. °dONLNdôÕ<ŸD*C
  6330.     °dONLNdõÂ<Ü*Bpascal OSErr BitMapToRegion (RgnHandle region, const BitMap *bMap)°dONLNdfiÔ<˙™*
  6331.              = 0xA8D7;
  6332. °dONLNdı<k*Assembly
  6333.     °dONLNd˛<(**_BitMapToRegion        OPWORD        $A8D7
  6334. °dONLNd)4<@á*The region will °dONLNd94á@)K!be built so that all one bits in °dONLNdZ3?5)íbMap°dONLNd^45@˛), are inside the region and all zero bits are°dONLNdã@<Lx(hZoutside of it.°dONLNdöY<e4*3As with all QuickDraw calls which change a region, °dONLNdÕX4dù)¯BitMapToRegion °dONLNd‹YùeΔ)i    requires °dONLNdÂYΔe˛)) you to pass°dONLNdÒf<r(éZ*an existing region (originally created by °dONLNdeq1)ƒ_NewRgn°dONLNd"f1rÅ)1).  If the region °dONLNd4fÅr˛)Pcannot be built due to an°dONLNdNr<~ò(öZJinsufficient heap space or a size greater than 32K, then the routine will °dONLNdòrò~˛(ö∂return an appropriate°dONLNdÆ~<ä—(¶ZUerror code and the region will be empty.  If the region would have exceeded 32K, the °dONLNd~—ä˛(¶Ô
  6335. error will°dONLNdã<óJ(≥Zbe °dONLNdäJñû) rgnTooBigErr°dONLNdãûó√)T (-500). ◊X◊
  6336. (ÏZSo Many Bitmaps, So Little Time(Ï1) of 2ˇ°¿Ù%%DSIDICT:_cv
  6337. currentdict /bu known {bu}if
  6338. userdict /_cv known not{userdict /_cv 30 dict put}if
  6339. _cv begin
  6340. /bdf{bind def}bind def
  6341. currentscreen/cs exch def/ca exch def/cf exch def
  6342. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  6343. /ss{//cf //ca //cs setscreen}bdf
  6344. /stg{ss setgray}bdf
  6345. /strgb{ss setrgbcolor}bdf
  6346. /stcmyk{ss cvcmyk}bdf
  6347. /min1{dup 0 eq{pop 1}if}bdf
  6348. end
  6349. currentdict /bn known {bn}if
  6350. †ø¥◊#ˇ ˇˇˇˇ#◊ 
  6351. IR,Times
  6352. .+6-Macintosh Technical Notes /4/˘
  6353. °dONLNd)∞*SThis function is useful for a number of situations where you have (or can produce) °dONLNdS∞)⁄(EŒa bitmap°dONLNd\*6Ä(R6representing an area.  °dONLNds*Ä6¿)h You can use ,
  6354. Courier°dONLNd)¿5ˇ)@    _CalcMask°dONLNdà*ˇ6⁄)?+ to produce such a bitmap.  Once you have a°dONLNd¥7Ce(_6region, you can °dONLNdƒ7eC)M!perform region operations (i.e., °dONLNdÂ6B:)ù_PtInRgn°dONLNdÌ7:CB)8, °dONLNdÔ6BBÅ)    _UnionRgn°dONLNd¯7ÅCó)?, or °dONLNd˝6óB÷)    _InsetRgn°dONLNd7÷C⁄)?)°dONLNdDP8(l6or call °dONLNdC8Oå)  _DragGrayRgn°dONLNdDåPœ)T, for example.°dONLNd+\hY(Ñ6CThis call is part of the 32-Bit QuickDraw INIT ($A8D7).  If you do °dONLNdn\Yh÷(Ñwnot wish to depend on 32°dONLNdÜ\÷h⁄)}-°dONLNdáiu)(ë6Bit °dONLNdãi)u),QuickDraw, then you can obtain a version of °dONLNd∑htj)flBitMapToRegion°dONLNd≈iju⁄)b in MPW object format°dONLNd€uÅ™(ù6Pwhich can be linked into an MPW program, by contacting Apple Software Licensing:°dONLNd/çÑôˇ+lApple Software Licensing°dONLNdKôÑ•* Apple Computer, Inc.,°dONLNdd•ѱ"* 20525 Mariani Avenue, M/S 38-I°dONLNdܱÑΩÔ* Cupertino, CA, 95014°dONLNdûΩÑ…œ* (408) 974-4667°dONLNd∞…Ñ’* AppleLink:  SW.LICENSE°dONLNd«‚Ó(
  6355. 63If you licensed the older version of this routine, °dONLNd˙·ÌM)ˆ    BitMapRgn°dONLNd‚MÓ¨)?, contact Software °dONLNd‚¨Ó⁄)_    Licensing°dONLNd Ó˙(62about receiving an updated version.  We recommend °dONLNdRÓ˙⁄(9&you update your application to use the°dONLNdy˙¥("6 new version as soon as possible.°dONLNdöØ*The new version is now named °dONLNd∑Ø)óBitMapToRegion°dONLNd≈Ø)b# to be consistent with the version °dONLNdËØ⁄)û    in 32-Bit°dONLNdÚ ,“(H6#QuickDraw and the MPW interfaces.  °dONLNd “,)∫
  6356. In addition, °dONLNd"+r)>BitMapToRegion°dONLNd0 r,⁄)b offers new features.°dONLNdG,8v(T6You can now pass °dONLNdX,v8⁄)^Ea one-bit pixelmap which has been coerced to a bitmap.  If you pass a°dONLNdû9E˚(a61pixelmap which is too large, then you will get a °dONLNdœ8˚Dk)„pixmapTooDeepErr°dONLNdfl9kEè)p (-148) °dONLNdÁ9èE⁄)$error.  You can°dONLNd˜FRW(n6also pass the °dONLNdEWQè)?portBits°dONLNd
  6357. FèRä)84 of a window, much like you would do with a call to °dONLNdAEäQ…)˚    _CopyBits°dONLNdJF…RÕ)?.°dONLNdL^j?(Ü6>There is a potential problem with this routine, since MPW 3.1 °dONLNdä^?j⁄(Ü]!include files contain information°dONLNd¨kw◊(ì6%about 32-Bit QuickDraw.  If you want °dONLNd—j◊v9)øBitMapToRegion°dONLNdflk9w=)b °dONLNd‡k=w⁄) to be available on all machines,°dONLNdwÉß(ü6then you must use the object °dONLNdwßÉ⁄)è;file from Software Licensing.  The problem is that when you°dONLNdZÉèí(´6Mcompile your application with MPW 3.1 or later, the 32-Bit QuickDraw version °dONLNdßÉíè⁄(´∞gets preference°dONLNd∑èõê(∑6over the object file.  You °dONLNd“èêõ´)xmust°dONLNd÷è´õˇ) comment out the °dONLNdÁèˇõ⁄)T/routine in the include files if you want to use°dONLNdú®Å(ƒ6the object file.  If you °dONLNd0úÅ®Ì)ionly care about using °dONLNdFõÌßO)lBitMapToRegion°dONLNdTúO®⁄)b on machines running 32-Bit°dONLNdp®¥Ë(–6)QuickDraw, then you need not do anything. ◊4◊˘
  6358. (Ï62) of 2(ÏmSo Many Bitmaps, So Little Timeˇ¢◊#ˇ ˇˇˇˇ#◊°d WORDS †å°d WORDR…†Ç 
  6359. /ZÅ#
  6360.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  6361. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  6362. .WIQkWIQk+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  6363. Ä({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  6364. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  6365.     l+&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  6366. BÄ(Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É°dWORD†ç
  6367. IR.°dONLNd{<éó(®Z'A Leading Cause of Color Cursor Cursing
  6368. °dONLNd(ç<úr*Imaging°dONLNd0çÄú˛(∏ûM.IM.ColorCursor
  6369. °dONLNdA®<¥t(–Z Revised by:°dONLNdM®Ñ¥¡)H
  6370. Alan Mimms°dONLNdX®æ¥˛(–‹ October 1989°dONLNde¥<¿q(‹Z Written by:°dONLNdq¥Ñ¿¡)H
  6371. Alan Mimms°dONLNd|¥Õ¿˛(‹Π   June 1989°dONLNdÜÃ<ÿù(ÙZIWorking with color cursors you create from scratch can cause headaches.  °dONLNdœÃùÿ˛(ÙªThis Technical Note°dONLNd„ÿ<‰Ç(Zmay help a bit.°dONLNdÛÂ<Òœ*
  6372. Changes since June 1989:°dONLNd œÒw)ì"  Added a warning about purgeable ,
  6373. Courier°dONLNd-‰w°)®'clut'°dONLNd3°Ғ)*  resources. X°dONLNd?
  6374. <Ò(2Z'If you’re building an application that °dONLNdf
  6375. Ò˛)µ4creates color cursors, you may encounter some quirks°dONLNdõ<"¿(>ZOpresent in Color QuickDraw that manifest themselves in hard-to-understand ways.°dONLNdÎ.<:º*If your cursor is, say, 15 °dONLNd.º:˛)Ä@pixels tall and 9 pixels wide, you might be tempted to use these°dONLNdG;<GÇ(cZvalues for the °dONLNdV:ÇF›)F
  6376. bounds.bottom°dONLNdc;›Gˆ)[ and °dONLNdh:ˆFJ) bounds.right°dONLNdt;JGí)T, respectively, °dONLNdÑ;íG˛)Hin your cursor’s pixel°dONLNdõG<SZ(oZmap.  °dONLNd°GZSz)Don’t°dONLNd¶GzSˇ) .  The problem is that when °dONLNd¬GˇS˛)Ö3the cursor’s image needs to be expanded (i.e., when°dONLNdˆS<_R({Zyou °dONLNd˙SR_˛)Wspecify a two bit-per-pixel cursor and the mouse pointer is on an eight-bit screen) the°dONLNdR_<kâ(àZ _SetCCursor°dONLNd]`âl÷)M trap rounds the °dONLNdn`÷l˛)M=width of the pixel map in such a way that you’ll get only the°dONLNd¨l<xZ(îZspace °dONLNd≤lZx˛)Rrequired for a 15 by 8 pixel map allocated for the expanded cursor data.  When the°dONLNdx<ÑÈ(†Z%cursor’s image is expanded into this °dONLNd*xÈÑ˛)≠8too-small expanded cursor data handle as a 15 by 9 pixel°dONLNdcÑ<ê(¨Z-map, something in your heap will get munched. °dONLNdëú<®˚*The cure is simple.  Make °dONLNd´ú˚®!)øcertain°dONLNd≤ú!®N)& that  °dONLNd∏úN®˛)-you always specify that the°dONLNd‘®<¥œ(—ZpixmapHandle^^.bounds°dONLNdÈ©œµ)ì be 16 by 16. °dONLNd˜©µt)L This will cause °dONLNd®t¥¡)Y _SetCCursor°dONLNd©¡µ˛)M  to properly°dONLNd µ<¡Ω(›Zallocate the expanded data °dONLNd;µΩ¡˛)ÅAarea, and all will be well in the land.  Since the amount of data°dONLNd}¬<Œ_(ÍZdrawn°dONLNdǬ_Œs)# for °dONLNdá¬sŒw)7a cursor is specified by the cursor’s pixel values and °dONLNdæ¡wÕ°(Íï'clut'°dONLNdƒ¬°Œ˛)* resource, trying to°dONLNdŸŒ<⁄ù(ˆZFsave a few bytes by making the bounds rectangle smaller than 16 by 16 °dONLNdŒù⁄˛(ˆªwouldn’t have been°dONLNd2⁄<ʰ(Zvery helpful anyway.°dONLNdGÚ<˛W*;Another potential problem is with the color cursor’s color °dONLNdÇÚW˛˛(u#table.  If you load the color table°dONLNd¶ˇ< W('Zfrom °dONLNd´ˇW a)a °dONLNd≠˛a
  6377. ã)
  6378. 'clut'°dONLNd≥ˇã ‹)* resource using °dONLNd√˛‹
  6379. ")Q
  6380. _GetCTable°dONLNdÕˇ" «)F , you should make sure that the °dONLNdÌ˛«
  6381. Ò)•'clut'°dONLNdÛˇÒ ˛)* is°dONLNd˜ <(3Z,marked non-purgeable while the color cursor °dONLNd# ˛)›/is in use.  If you do not take this precaution,°dONLNdS<$¥(@Zbombs will occur if your °dONLNdl¥#fi)x'clut'°dONLNdrfi$Ü)*$ gets purged at in inopportune time. ◊X◊
  6382. (ÏZ'A Leading Cause of Color Cursor Cursing(Ï1) of 1ˇ°¿Ù%%DSIDICT:_cv
  6383. currentdict /bu known {bu}if
  6384. userdict /_cv known not{userdict /_cv 30 dict put}if
  6385. _cv begin
  6386. /bdf{bind def}bind def
  6387. currentscreen/cs exch def/ca exch def/cf exch def
  6388. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  6389. /ss{//cf //ca //cs setscreen}bdf
  6390. /stg{ss setgray}bdf
  6391. /strgb{ss setrgbcolor}bdf
  6392. /stcmyk{ss cvcmyk}bdf
  6393. /min1{dup 0 eq{pop 1}if}bdf
  6394. end
  6395. currentdict /bn known {bn}if
  6396. †ø◊#ˇ ˇˇˇˇ#◊†Ç 
  6397. /ZÅ#
  6398.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  6399. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  6400. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  6401. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  6402. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  6403.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  6404. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  6405. IR.°dONLNdn<Å(õZColor Manager Q&As
  6406. °dONLNdÄ<èr*Imaging°dONLNdÄeè˛(´ÉM.IM.ColorMgr.Q&As
  6407. °dONLNd.õ<ßt(√Z Revised by:°dONLNd:õÑߡ)HDeveloper Support Center°dONLNdSõæß˛(√‹ October 1992°dONLNd`ß<≥q(œZ Written by:°dONLNdlßÑ≥ˇ)HDeveloper Support Center°dONLNdÖßæ≥˛(œ‹ October 1990°dONLNdíø<À⁄(ÁZThis Technical Note contains a °dONLNd±ø⁄À˛)û9collection of Q&As relating to a specific topic—questions°dONLNdÎÀ<◊†(ÛZGyou’ve sent the Developer Support Center (DSC) along with answers from °dONLNd2À†◊˛(Ûæthe DSC engineers.°dONLNdE◊<„u(ˇZ
  6408. While DSC °dONLNdO◊u„˛)9Lengineers have checked the Q&A content for accuracy, the Q&A Technical Notes°dONLNdú„<Ôq( Z don’t have °dONLNdß„qÔ˛)5Qthe editing and organization of other Technical Notes. The Q&A function is to get°dONLNd˘Ô<˚Ÿ(Znew technical information and °dONLNdÔŸ˚˛)ù6updates to you quickly, saving the polish for when the°dONLNdN˚<(#Z,information migrates into reference manuals.°dONLNd{<k*:Q&As are now included with Technical Notes to make access °dONLNdµk˛(;âto technical updates easier for°dONLNd’<+.(GZ/you. If you have comments or suggestions about °dONLNd.+˛)Ú*Q&A content or distribution, please let us°dONLNd/+<7\(SZknow °dONLNd4+\7˛) Iby sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical°dONLNd~7<Ci(_Z9questions about Q&A content to DEVSUPPORT for resolution.°dONLNd∏O<[«*NNew Q&As and Q&As revised this month are marked with a bar in the side margin."n  ÜXÜ
  6409. °dONLNdÄ<èç*4.Color Manager search and complement procedures
  6410. °dONLNd6è<õb* Written:°dONLNd?èàõ¨)L10/7/91°dONLNdGõ<ßÅ(√ZLast reviewed:°dONLNdVõàߨ)L11/6/91°dONLNd^≥<øÖ(€Z The AddComp °dONLNdj≥Öø˙)IHcomplement procedure description in Inside Macintosh Volume V, pages 145°dONLNd≤≥˙ø˛(€-°dONLNd≥ø<À
  6411. (ÁZ*147, is vague. The last paragraph on page °dONLNd›ø
  6412. À˛)—-V-146 states, “Complement procedures work the°dONLNd À<◊Q(ÛZ:same as search procedures,” but SearchProc is a function, °dONLNdEÀQ◊˛(Ûo!CompProc is a procedure, and each°dONLNdg◊<„(ˇZYhave a different number of parameters. What else does CompProc need as input and on exit?°dONLNd¡„<ÔN* ___°dONLNd≈˚<‰*CompProc should be declared as °dONLNd‰˚‰˛)®2a Pascal FUNCTION that returns a Boolean. The code°dONLNd<v(/Z?performs a CLR.B for the return value of CompProc, so treat it °dONLNdVv˛(/îlike SearchProc. CompProc°dONLNdp<æ(;ZQonly uses one parameter since its one parameter is a VAR, which means it will be °dONLNd¡æ˛(;‹
  6413. replaced with°dONLNdœ<+’(GZVthe correct complementary color. SearchProc returns an index in its second parameter, °dONLNd%’+˛(GÛwhich is°dONLNd.+<7Ÿ(SZ why it needs a second parameter.
  6414. °dONLNdOO<^d*'*Using ResEdit to get Apple icon RGB values
  6415. °dONLNdz^<jb* Written:°dONLNdÉ^àj¶)L1/7/92°dONLNdäj<vÅ(íZLast reviewed:°dONLNdôjàv¶)L8/1/92°dONLNd†Ç<éÇ(™Z=I am trying to find the RGB values for Apple's standard icon °dONLNd›ÇÇé˛(™†colors. I can’t find this°dONLNd˜é<öj(∂Z@information in any documentation. Is this information available?°dONLNd8ö<¶N* ___ ◊X◊
  6416. **Color Manager Q&As(Ï1) of 2ˇ°¿Ù%%DSIDICT:_cv
  6417. currentdict /bu known {bu}if
  6418. userdict /_cv known not{userdict /_cv 30 dict put}if
  6419. _cv begin
  6420. /bdf{bind def}bind def
  6421. currentscreen/cs exch def/ca exch def/cf exch def
  6422. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  6423. /ss{//cf //ca //cs setscreen}bdf
  6424. /stg{ss setgray}bdf
  6425. /strgb{ss setrgbcolor}bdf
  6426. /stcmyk{ss cvcmyk}bdf
  6427. /min1{dup 0 eq{pop 1}if}bdf
  6428. end
  6429. currentdict /bn known {bn}if
  6430. †ø
  6431. t◊#ˇ ˇˇˇˇ#◊ 
  6432. IR,Times
  6433. .+6-Macintosh Technical Notes /4/˘
  6434. °dONLNd)5ß*$TWhile the RGB values for the standard Apple icon colors (and other standard palette °dONLNdT)ß5⁄(Q≈ colors) are°dONLNd`5Afi(]6)not explicitly documented, they are easy °dONLNdâ5fiA⁄)Δ3to obtain with ResEdit 2.1.1. In any resource file,°dONLNdΩAMÛ(i6.create and open a new 'pltt' resource. Choose °dONLNdÎAÛM⁄)€-Load Colors from the pltt menu and pick Apple°dONLNdMYø(u6$Icon Colors, and a standard palette °dONLNd=MøY⁄)ß<will be created. Selecting a color will reveal its component°dONLNdzYe:(Å6values.°dONLNdÇq}ú*PResEdit 2.1.1 is available on the latest Developer CD Series disc and from APDA.
  6435. °dONLNd”ï§c*'.Macintosh Color Manager versus Palette Manager
  6436. °dONLNd§∞>* Written:°dONLNd §d∞Ç)L1/1/90°dONLNd∞º](ÿ6Last reviewed:°dONLNd!∞dºÇ)L8/1/92°dONLNd(»‘Z(6 When should °dONLNd4»Z‘⁄)BJthe Macintosh Color Manager be used and when should the Palette Manager be°dONLNd‘‡3(¸6used?°dONLNdÖ‡Ï** ___°dONLNdâ¯V*CThe Palette Manager is by far the friendlier and more versatile of °dONLNdïV⁄( tthe two if your application°dONLNd˰(,6Xuses different colors than the default system colors. It provides all the functionality °dONLNd@°⁄(,ø you need to°dONLNdLå(86Ncustomize and animate the colors in your application. You shouldn’t ever need °dONLNdöå⁄(8™to use the Color°dONLNd´(å(D6IManager unless you require custom color search and complement functions. °dONLNdÙå(⁄(D™When using the°dONLNd(4ñ(P6PPalette Manager, applications will maintain their respective color environments °dONLNdS(ñ4⁄(P¥safely as they°dONLNdb4@H(\67move back and forth from foreground to background, and °dONLNdô4H@⁄(\ffrom one screen to another.°dONLNdµ@L¨(h6PAccomplishing this with the Color Manager calls is not worth the effort or very °dONLNd@¨L⁄(h     safe. For°dONLNdLXŸ(t6]additional information, see the Palette Manager chapter in Inside Macintosh Volumes V and VI. ◊4◊˘
  6437. (Ï62) of 2(ÏüColor Manager Q&Asˇ¸◊#ˇ ˇˇˇˇ#◊†Ç 
  6438. /ZÅ#
  6439.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  6440. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  6441. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  6442. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  6443. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  6444.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  6445. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  6446. IR.°dONLNdn<Å(õZColor QuickDraw Q&As
  6447. °dONLNdÄ<èr*Imaging°dONLNdÄkè˛(´âM.IM.ColorQD.Q&As
  6448. °dONLNd/õ<ßt(√Z Revised by:°dONLNd;õÑߡ)HDeveloper Support Center°dONLNdTõæß˛(√‹ October 1992°dONLNdaß<≥q(œZ Written by:°dONLNdmßÑ≥ˇ)HDeveloper Support Center°dONLNdÜßæ≥˛(œ‹ October 1990°dONLNdìø<À⁄(ÁZThis Technical Note contains a °dONLNd≤ø⁄À˛)û9collection of Q&As relating to a specific topic—questions°dONLNdÏÀ<◊†(ÛZGyou’ve sent the Developer Support Center (DSC) along with answers from °dONLNd3À†◊˛(Ûæthe DSC engineers.°dONLNdF◊<„u(ˇZ
  6449. While DSC °dONLNdP◊u„˛)9Lengineers have checked the Q&A content for accuracy, the Q&A Technical Notes°dONLNdù„<Ôq( Z don’t have °dONLNd®„qÔ˛)5Qthe editing and organization of other Technical Notes. The Q&A function is to get°dONLNd˙Ô<˚Ÿ(Znew technical information and °dONLNdÔŸ˚˛)ù6updates to you quickly, saving the polish for when the°dONLNdO˚<(#Z,information migrates into reference manuals.°dONLNd|<k*:Q&As are now included with Technical Notes to make access °dONLNd∂k˛(;âto technical updates easier for°dONLNd÷<+.(GZ/you. If you have comments or suggestions about °dONLNd.+˛)Ú*Q&A content or distribution, please let us°dONLNd0+<7\(SZknow °dONLNd5+\7˛) Iby sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical°dONLNd7<Ci(_Z9questions about Q&A content to DEVSUPPORT for resolution.°dONLNdπO<[«*NNew Q&As and Q&As revised this month are marked with a bar in the side margin."n  ÜXÜ
  6450. °dONLNdÄ<èÌ*4?Using a Macintosh PICT file that’s larger than available memory
  6451. °dONLNdHè<õb* Written:°dONLNdQèàõ¨)L6/18/90°dONLNdYõ<ßÅ(√ZLast reviewed:°dONLNdhõàߨ)L9;/24/91°dONLNdq≥<øa(€Z9How can I read a 2 MB PICT file into only 1 MB of memory?°dONLNd´ø<ÀN* ___°dONLNdØ◊<„é*EYou can’t read it in since you don’t have enough memory, but drawing °dONLNdÙ◊鄲(ˇ¨the picture contained in°dONLNd
  6452. „<Ô¥( Zthe file using a technique °dONLNd(„¥Ô˛)xBcalled “spooling” increases your chances of using a 2 MB PICT file°dONLNdkÔ<˚V(Zwith °dONLNdpÔV˚˛)L1 MB memory. Spooling is documented in the Color QuickDraw chapter of Inside°dONLNdΩ˚<È(#Z!Macintosh Volume V (pages 88-89).
  6453. °dONLNdfl<.Z*'+Getting a single scan line from a PICT file
  6454. °dONLNd .<:b* Written:°dONLNd.à:¨)L6/18/90°dONLNd:<FÅ(bZLast reviewed:°dONLNd+:àF¨)L9/24/91°dONLNd3R<^o(zZCIs there any way to obtain a particular scan line from a PICT file?°dONLNdw^<jN* ___°dONLNd{v<ÇÔ*VA PICT file may contain more than just pixmaps, so getting one scan line out of it is °dONLNd—vÔDz(û
  6455. not°dONLNd’Ç<é(™Z*possible. The file may also contain other °dONLNdˇÇé˛)…2elements that overlap, such as rects and arcs. The°dONLNd2é<ö•(∂ZLonly way to obtain a single line is to draw it offscreen and then, once the °dONLNd~é•ö˛(∂√whole image is in°dONLNdêö<¶$(¬Z/memory, you can go and study individual pixels. ◊X◊
  6456. **Color QuickDraw Q&As(Ïˇ1) of 29ˇ°¿Ù%%DSIDICT:_cv
  6457. currentdict /bu known {bu}if
  6458. userdict /_cv known not{userdict /_cv 30 dict put}if
  6459. _cv begin
  6460. /bdf{bind def}bind def
  6461. currentscreen/cs exch def/ca exch def/cf exch def
  6462. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  6463. /ss{//cf //ca //cs setscreen}bdf
  6464. /stg{ss setgray}bdf
  6465. /strgb{ss setrgbcolor}bdf
  6466. /stcmyk{ss cvcmyk}bdf
  6467. /min1{dup 0 eq{pop 1}if}bdf
  6468. end
  6469. currentdict /bn known {bn}if
  6470. †ø`◊#ˇ ˇˇˇˇ#◊ 
  6471. IR,Times
  6472. .+6-Macintosh Technical Notes /4/˘
  6473. °dONLNd5D**3'Determining pixel depth from PICT files
  6474. °dONLNd(DP>* Written:°dONLNd1DdPà)L6/20/90°dONLNd9P\](x6Last reviewed:°dONLNdHPd\à)L9/17/91°dONLNdPht<(ê6>How do you find out the pixel size of a PICT file on the disk?°dONLNdètÄ** ___°dONLNdìåòz*GA picture is by nature independent of depth. For example, you can have °dONLNd⁄åzò⁄(¥òa picture containing°dONLNdÔò§x(¿6HDrawRects and LineTos and therefore lacking of any info regarding depth.°dONLNd8∞ºx*KOn the other hand, if the picture you are looking at has pixmap opcodes in °dONLNdÉ∞xº⁄(ÿñit, then each pixmap°dONLNdòº»w(‰6Icontains its own pixel size and in this case a picture can have a number °dONLNd·ºw»⁄(‰ïof depths associated°dONLNdˆ»‘:(6with it.°dONLNdˇ‡ÏŸ*+If you want to see the pixel size for each °dONLNd*‡ŸÏ⁄)¡6pixmap opcode in a picture, replace all the bottleneck°dONLNdaϯ¿(6\routines and every time the bitsProc is called you can see the pixmap and get the info out. °dONLNdΩÏ¿¯⁄(fiSince°dONLNd√¯ñ( 6the picture is in a file, you °dONLNd·¯ñ⁄)~Acan use the spooling technique described in the QuickDraw chapter°dONLNd#ø(,6!in Inside Macintosh Volume V. Be °dONLNdDø⁄)ß;ready to deal with multiple, possibly different, pixmaps as°dONLNdÄs(86Iwell as direct pixmaps if the picture was created under 32-bit QuickDraw.°dONLNd (4»*Q”KnowsPICT,” on the Developer CD Series disc, extracts this kind of information. °dONLNd(»4⁄(PÊThe°dONLNd4@=(\6?System 7.0 Picture Utilities package gets this information too.
  6475. °dONLNd_Xg*' Direct RGB PICT file compression
  6476. °dONLNdÄgs>* Written:°dONLNdâgdsé)L10/24/90°dONLNdís](õ6Last reviewed:°dONLNd°sdà)L2/14/91°dONLNd©ãóÃ(≥6VHow are bits packed in direct RGB PICT files created by 32-Bit QuickDraw? I looked at °dONLNdˇãÃó⁄(≥Íthe°dONLNdó£∞(ø6KMacintosh Technical Note “Things You Wanted To Know about _PackBits…”, but °dONLNdNó∞£÷(øŒthis run°dONLNdVó÷£⁄)&-°dONLNdW£Ø(À62length encoded compression is clearly inefficient °dONLNdâ£Ø⁄)Ó+for cases where pixelSize is greater than 8°dONLNdµØª0(◊6bits. °dONLNdªØ0ª⁄)XI write software for machines other than Macintosh that decodes PICT files; therefore, I°dONLNdª«(„65cannot issue any QuickDraw calls such as _unpackBits.°dONLNdJ«”** ___°dONLNdNflÎV*
  6477. You’re quite °dONLNd[flVÎ⁄)>Pright; compressing direct pixels using straight run-length encoding doesn’t work°dONLNd¨Î˜Q(6Avery well. Fortunately, direct pixel maps aren’t compressed this °dONLNdÌÎQ˜⁄(oway. Compression schemes°dONLNd˜)(63are discussed in Inside Macintosh Volume VI in the °dONLNd9˜)⁄(G section titled “The New OpCodes:°dONLNdZu(+6Expanded Format.”°dONLNdl'»*WIn short, if the packType field holds the value 1, then no compression is done at all. °dONLNd√»'⁄(CÊThe°dONLNd«'3±(O6Wcomplete pixel image is saved in the PICT. If the packType field holds the value 2 and °dONLNd'±3⁄(Oœ    the pixel°dONLNd(3?‘([6bmap is 32-bits per pixel, then all that’s done is that the alpha-channel byte is removed. So this:,
  6478. Courier
  6479.     °dONLNdãKV*/                       00 FF FF FF  00 FF FF FF
  6480. °dONLNdªamj*is compressed to:
  6481.     °dONLNdÕyÑÂ*)                       FF FF FF  FF FF FF
  6482. °dONLNd˜èõ}*If the packType field °dONLNd    
  6483. è}õ⁄)eIholds the value 3 and the pixel map is 16 bits per pixel, then run-length°dONLNd    WõßF(√6    encoding °dONLNd    `õFß⁄).Sis done, but not through PackBits. Instead, a run-length encoding algorithm private ◊4◊˘
  6484. (Ï62) of 29(ÏîColor QuickDraw Q&Asˇ◊#ˇ ˇˇˇˇ#◊ 
  6485. IR,Times
  6486. .+Z-Developer Support Center(-Ê October 1992 /X/
  6487. °dONLNd<)(EZ%to QuickDraw is used. This algorithm °dONLNd%)˛)«/is very similar to PackBits, but where PackBits°dONLNdU)<5œ(QZcompresses runs of bytes, this °dONLNdt)œ5˛)ì=routine compresses runs of words. The format of the resulting°dONLNd≤5<A¿(]Zdata is exactly the same as °dONLNdŒ5¿A˛)Ñ:described in the Technical Note “Things You Wanted To Know°dONLNd    A<M,(iZ1about _PackBits…”, but you’ll get words instead. °dONLNd:A,M˛)*To build on the example in this Tech Note,°dONLNdeM<Y[(uZ?lets say the 16-bit pixel image begins with these pixel values:,
  6488. Courier
  6489.     °dONLNd•e<pw*?    AAAA AAAA AAAA 8080 0000 2A2A AAAA AAAA AAAA AAAA 8080 0000°dONLNdÂo<zw*
  6490. ?    2A2A 2222 AAAA AAAA AAAA AAAA AAAA AAAA AAAA AAAA AAAA AAAA°dONLNd%É<éΩ*MAfter being packed by QuickDraw’s internal compression routine, this becomes:°dONLNdsó<¢s*     FE AAAA°dONLNd°<¨•*
  6491.     02 8080 0000 2A2A°dONLNdï´<∂s*
  6492.     FD AAAA°dONLNd°µ<¿æ*
  6493.     03 8080 0000 2A2A 2222°dONLNdºø< s*
  6494.     F7 AAAA
  6495. °dONLNd»’<·F*or
  6496.     °dONLNdÀÌ<¯Ü*B    FEAA AA02 8080 0000 2A2A FDAA AA03 8080 0000 2A2A 2222 F7AA AA°dONLNd˜<h*
  6497. <    *      *                 *      *                      *
  6498. °dONLNdK
  6499. <**where the asterisks mark the flag-counter °dONLNdu
  6500. ˛)À2bytes. Notice that you can’t assume that the pixel°dONLNd®<%Q(AZ:values are word-aligned. PackBits packs data 127 bytes at °dONLNd‚Q%˛(Ao%a time, though it will do this for up°dONLNd%<1T(MZ;to 32,767 total bytes. Similarly, the internal compression °dONLNdC%T1˛(Mr!routine packs data 127 words at a°dONLNde1<=T(YZtime.°dONLNdkI<U°*If the packType field °dONLNdÅI°U˛)eIholds the value 4 and the pixel map is 32-bits per pixel, then run-length°dONLNdÀU<a÷(}Zencoding via PackBits is done, °dONLNdÍU÷a˛)ö:but only after some preprocessing is done. QuickDraw first°dONLNd%a<mª(âZNrearranges the color components of the pixels so that each color component of °dONLNdsaªm˛(âŸevery pixel is°dONLNdÇm<yz(ïZ
  6501. consecutive. °dONLNdèmzy˛)>PSo the following four pixels (the row below the pixel values indicates a = alpha°dONLNd‡y<ÖQ(°Z=channel, r = red, g = green, b = blue, and the pixel offset):
  6502.     °dONLNdë<úr*>            00 FF FF FF  00 FF C0 00  00 FF 80 00  00 C0 80 00°dONLNd]õ<¶r*
  6503. >            a0 r0 g0 b0  a1 r1 g1 b1  a2 r2 g2 b2  a3 r3 g3 b3
  6504. °dONLNdú±<ΩØ*is rearranged to become:
  6505.     °dONLNdµ…<‘1*1            FF FF FF C0  FF C0 80 80  FF 00 00 00°dONLNdÁ”<fi1*
  6506. 1            r0 r1 r2 r3  g0 g1 g2 g3  b0 b1 b2 b3
  6507. °dONLNdÈ<ı´*The first four bytes are °dONLNd2È´ı˛)oGthe red components of the four pixels, the next four bytes indicate the°dONLNdzı<Ü(ZBgreen components of the four pixels, and so on. The alpha channel °dONLNdºıܲ(§isn’t included unless the°dONLNd÷<
  6508. 2()Z4cmpCount field contains 4 rather than the normal 3. °dONLNd
  6509. 2
  6510. ˛)ˆ*If cmpCount contains 4, then all the alpha°dONLNd5
  6511. <◊(5Z channel bytes are placed before °dONLNdU
  6512. ◊˛)õ<the red bytes. Once this is done, then PackBits is called to°dONLNdí<%…(AZcompress the rearranged data.°dONLNd∞1<=¶*GThose are the only four compression schemes (including no compression) °dONLNd˜1¶=˛(Yƒthat are supported°dONLNd    
  6513. =<I¨(eZfor direct pixel maps in °dONLNd    #=¨I˛)pBPICTs. As always, reading PICTs yourself puts you in danger of not°dONLNd    fI<Uh(qZ9being able to read PICTs generated by future versions of °dONLNd    üIhU˛(qÜQuickDraw. For compatibility°dONLNd    ºU<aÑ(}Zreasons, these °dONLNd    ÀUÑa˛)HJcompression algorithms as I’ve described them probably can’t change in the°dONLNd
  6514. a<mπ(âZOfuture. It’s possible that new values for packType could be implemented though.°dONLNd
  6515. fy<Ö]*X-Ref:°dONLNd
  6516. mÖ<ë∞* EMacintosh Technical Note “Things You Wanted To Know about _PackBits…” ◊X◊
  6517. *?Color QuickDraw Q&As(Ïˇ3) of 29ˇ>◊#ˇ ˇˇˇˇ#◊ 
  6518. IR,Times
  6519. .+6-Macintosh Technical Notes /4/˘
  6520. °dONLNd,Á*Saving 32-bit Macintosh PICTs
  6521. °dONLNd,8>* Written:°dONLNd',d8é)L10/30/90°dONLNd08D](`6Last reviewed:°dONLNd?8dDà)L2/20/91°dONLNdGP\S(x6@I am using a packType=4 and have several questions about saving °dONLNdáPS\⁄(xqMacintosh 32- bit images in°dONLNd£\h_(Ñ6a PICT format:°dONLNd≤tÄô*L(1) What are the ramifications of using cmpCount=3 as opposed to cmpCount=4?°dONLNdˇåò7*=(2) How is the pixData actually stored? According to several °dONLNd<å7ò⁄(¥U#references, each line is run-length°dONLNd`ò§/(¿6:encoded; that is, [byteCount][data]. If rowBytes>250 then °dONLNdöò/§⁄(¿M"byteCount is a word. After looking°dONLNdΩ§∞ú(Ã6at several examples, I came °dONLNdŸ§ú∞⁄)ÑCto the conclusion that you are actually using packBits and that the°dONLNd∞ºfi(ÿ6(term “run-length” encoded is a misnomer.°dONLNdFº»** ___°dONLNdJ‘‡e*B(1) The difference between using cmpCount=3 or cmpCount=4 is that °dONLNdå‘e‡⁄(¸Éin the first case only the°dONLNd߇Ï(64R, G and B values are stored in the picture; in the °dONLNd€‡Ï⁄)Ï+second case QuickDraw stores in the picture°dONLNdϯ<(6:the alpha channel plus R, G and B. cmpCount=4 can be used °dONLNdAÏ<¯⁄(Z!when it is important to also save°dONLNdc¯=( 6=the alpha channel (as when you have some flags stored there).°dONLNd°µ*!(2) Unless rowBytes is less than °dONLNd¬µ⁄)ù:8, the PixMap is compressed using PackBits, and the length°dONLNd˝((D62is a word or a byte depending on rowBytes, but it °dONLNd/(⁄(D:$always refers to the number of bytes°dONLNdT(4ã(P6Ocomprising one scan line. My guess is that “run-length encoding” refers to the °dONLNd£(ã4⁄(P©fact that pictures°dONLNd∂4@Õ(\6&have data organized one row at a time.°dONLNd›LX’*[To show how direct RGB PixMaps are stored inside a picture, I am including the decoding of °dONLNd8L’X⁄(tÛa°dONLNd:Xdz(Ä6picture that I created °dONLNdQXzd⁄)bEto show how the different packing schemes change the resulting PixMap°dONLNdódp≥(å6Yopcode data. First I created a direct RGB PixMap and drew three lines into it. The first °dONLNdd≥p⁄(å—    line is 8°dONLNd˙p|ö(ò6Ppixels long with a color of {0x1111,0xAAAA, 0x7777}, the third line is 8 pixels °dONLNdJpö|⁄(ò∏ of {0xFFFF,°dONLNdV|àC(§60x3333, °dONLNd^|Cà⁄)+S0xBBBB} and the line in between is two pixels of the first color then two pixels of°dONLNd≤àî0(∞6;the second color and so on until you make 8 pixels. Then I °dONLNdÌà0î⁄(∞N"created a picture made of CopyBits°dONLNdî†î(º6Jcalls copying the same lines but using different packing schemes. Finally °dONLNdZîî†⁄(º≤ I dumped the°dONLNdg†¨e(»6Dcontents and the result is what you see here. I have put comments I °dONLNd´†e¨⁄(»Éthink help make it clear°dONLNdƒ¨∏(‘65how the packing scheme of choice changes the results.°dONLNd˙ƒ– *I °dONLNd¸ƒ –⁄)Rrecommend that you have the Inside Macintosh Volume V QuickDraw chapter at hand to°dONLNdO–‹X(¯6Ccheck the opcodes and data associated with them. If you had Inside °dONLNdí–X‹⁄(¯vMacintosh Volume VI then°dONLNd´‹ˈ(6+you wouldn't need to also check the 32-Bit °dONLNd÷‹ˆË⁄)fi(QuickDraw docs for the direct RGB PixMap°dONLNdˇËÙZ(6=opcodes. The Technical Note “Things You Wanted To Know about °dONLNd    <ËZÙ⁄(x_PackBits…” gives details°dONLNd    VÙ¬(6#on how the packed data is arranged.,
  6522. Courier
  6523.     °dONLNd    z q*E0256 0000 0000 0008 0008                   /* size and rect        */°dONLNd    ¿ +q*E0011 02FF 0C00 FFFF FFFF                   /* PICT2 Header         */°dONLNd
  6524. *5ê*
  6525. 0000 0000 0000 0000 0008°dONLNd
  6526. 4?ê*
  6527. 0000 0008 0000 0000 0000°dONLNd
  6528. 8HSq*E001E                                       /* Default hilite       */°dONLNd
  6529. ~\gq*E001A FFFF 3333 BBBB                        /* RGB Fore Color       */°dONLNd
  6530. ƒp{q*E0001 000A 8001 8001 7FFF 7FFF              /* ClipRgn              */°dONLNd
  6531. Ñèû*N009A              /* direct pixels opcode; see IM VI QD chapter for details */°dONLNd Yéôû*
  6532. N0000 00FF 8020 0000 0000 0003 0008 0000    /* See IM V or VI QuickDraw chapter°dONLNd ®ò£"*
  6533. */°dONLNd ´¢≠è*
  6534. K0001 0000 0000 0048 0000 0048 0000 0010    /* packType 0001 = no packing */ ◊4◊˘
  6535. *#4) of 29(ÏîColor QuickDraw Q&Asˇ¶◊#ˇ ˇˇˇˇ#◊ 
  6536. IR,Times
  6537. .+Z-Developer Support Center(-Ê October 1992 /X/,
  6538. Courier
  6539.     °dONLNd<(ˇ(DZ'0020 0003 0008 0000 0000 006D A7DC 0000°dONLNd('<2ˇ*
  6540. '0000 0000 0000 0003 0008 0000 0000 0003°dONLNdP1<<i*
  6541.     0008 0000°dONLNdZE<P©*I0011 AA77 0011 AA77 0011 AA77 0011 AA77    /* line one xRGB after xRGB */°dONLNd§O<Zˇ*
  6542. '0011 AA77 0011 AA77 0011 AA77 0011 AA77°dONLNdÃc<nÅ*A0011 AA77 0011 AA77 00FF 33BB 00FF 33BB    /* second line same */°dONLNdm<xˇ*
  6543. '0011 AA77 0011 AA77 00FF 33BB 00FF 33BB°dONLNd6Å<åÅ*A00FF 33BB 00FF 33BB 00FF 33BB 00FF 33BB    /* third line same  */°dONLNdxã<ñˇ*
  6544. '00FF 33BB 00FF 33BB 00FF 33BB 00FF 33BB°dONLNd†ü<™∏*L009A                                       /* same direct pixels opcode   */°dONLNdÌ©<¥ˇ*
  6545. '0000 00FF 8020 0000 0000 0003 0008 0000°dONLNd≥<æ∏*
  6546. L0002 0000 0000 0048 0000 0048 0000 0010    /* packType 2 = fourth byte off*/°dONLNdbΩ<»ˇ*
  6547. '0020 0003 0008 0000 0000 006D A7DC 0000°dONLNdä«<“ˇ*
  6548. '0000 0000 0000 0003 0008 0003 0000 0006°dONLNd≤—<‹i*
  6549.     0008 0000°dONLNdºÂ<∏*L11AA 7711 AA77 11AA 7711 AA77              /* one line of RGB after RGB   */°dONLNd    Ô<˙∏*
  6550. L11AA 7711 AA77 11AA 7711 AA77              /* compare with previous       */°dONLNdV<Y*911AA 7711 AA77 FF33 BBFF 33BB              /* same here*/°dONLNdê
  6551. <Õ*
  6552. 11AA 7711 AA77 FF33 BBFF 33BB°dONLNdÆ!<,Y*9FF33 BBFF 33BB FF33 BBFF 33BB              /* and here */°dONLNdË+<6Õ*
  6553. FF33 BBFF 33BB FF33 BBFF 33BB°dONLNd?<Jh*<009A                                       /* bits opcode */°dONLNdCI<Tˇ*
  6554. '0000 00FF 8020 0000 0000 0003 0008 0000°dONLNdkS<^ö*
  6555. F0004 0000 0000 0048 0000 0048 0000 0010    /* packType 4 = pack     */°dONLNd≤]<hö*
  6556. F0020 0003 0008 0000 0000 006D A7DC 0000    /* componentCount = 3    */°dONLNd˘g<rö*
  6557. F0000 0000 0000 0003 0008 0006 0000 0009    /* R,G and B separated   */°dONLNd@q<|i*
  6558.     0008 0000°dONLNdJÖ<ê÷*R                    /* for details on packed data see Tech Note referenced above*/°dONLNdùè<öü*
  6559. G06                  /* first line made of 6 bytes including count    */°dONLNdÂô<§T*
  6560. 8F9 11F9 AAF9 77     /* -(-7)+1 of 11, -(-7)+1 of AA, and°dONLNd£<Æü*
  6561. G                                   -(-7)+1 of 77 -> 8 RGB triplets   */°dONLNdf≠<∏ü*
  6562. G19                                   /* second row made of $19 bytes */°dONLNdÆ∑<¬r*
  6563. >1711 11FF FF11 11FF FFAA AA33 33AA AA33 3377 77BB BB77 77BB BB°dONLNdÌ¡<Ãö*
  6564. F                                           /* $17+1 unpacked values */°dONLNd4À<÷¬*
  6565. N06                                         /* third line same as first      */°dONLNdÉ’<‡¬*
  6566. NF9FF F933 F9BB                             /* repeated R and B and G values */°dONLNd“È<Ùï*E009A                                          /* bits opcode again */°dONLNdÛ<˛ˇ*
  6567. '0000 00FF 8020 0000 0000 0003 0008 0000°dONLNd@˝<¬*
  6568. N0004 0000 0000 0048 0000 0048 0000 0010       /* same packing = 4 but       */°dONLNdè<¬*
  6569. N0020 0004 0008 0000 0000 006D A7DC 0000       /* component count = 4        */°dONLNdfi<¬*
  6570. N0000 0000 0000 0003 0008 0009 0000 000C       /* alpha channel, R, G, and B */°dONLNd    -<&i*
  6571.     0008 0000°dONLNd    7/<:r*>08                                            /* first line */°dONLNd    v9<D†*
  6572. F9 00F9 11F9 AAF9 77°dONLNd    ãC<N¬*
  6573. N                /* same as before but packing the high byte (00 value) also */°dONLNd    ⁄M<X¬*
  6574. N1B    /* second line first has -(-7)+1 '00' and then the same line as above */°dONLNd
  6575. )W<bã*
  6576. CF900 1711 11FF FF11 11FF FFAA AA33 33AA AA33 3377 77BB BB77 77BB BB°dONLNd
  6577. ma<l∏*
  6578. L08                                            /* third line same as first */°dONLNd
  6579. ∫k<võ*
  6580. F900 F9FF F933 F9BB°dONLNd
  6581. Œu<Äw*
  6582. ?00FF                                          /* end of PICT */
  6583. °dONLNd ã<óB*9A section of the code that produces this picture follows:
  6584.     °dONLNd H£<Æ@*4    RGBColor    oneColor = {0x1111, 0xaaaa, 0x7777}, ◊X◊
  6585. *"Color QuickDraw Q&As(Ïˇ5) of 29ˇñ◊#ˇ ˇˇˇˇ#◊ 
  6586. IR,Times
  6587. .+6-Macintosh Technical Notes /4/˘,
  6588. Courier
  6589.     °dONLNd(*2                twoColor = {0xffff,0x3333,0xbbbb};°dONLNd31<î*L    SetGWorld(GgwPtr, nil);                   /* set the offscreen GWorld */°dONLNdÄEPÔ*+    if ( LockPixels(GgwPtr -> portPixMap) )°dONLNd¨OZ1*
  6590.     {°dONLNd≤cn€*'        EraseRect(&(GgwPtr->portRect));°dONLNd⁄wÇ∏*         RGBForeColor(&oneColor);°dONLNd˚Åå|*
  6591.         MoveTo(0,0);°dONLNdãñ|*
  6592.         LineTo(7,0);°dONLNd%ï†|*
  6593.         MoveTo(0,1);°dONLNd:ü™|*
  6594.         LineTo(1,1);°dONLNdO©¥∏*
  6595.          RGBForeColor(&twoColor);°dONLNdp≥æ|*
  6596.         MoveTo(2,1);°dONLNdÖΩ»|*
  6597.         LineTo(3,1);°dONLNdö«“∏*
  6598.          RGBForeColor(&oneColor);°dONLNdª—‹|*
  6599.         MoveTo(4,1);°dONLNd–€Ê|*
  6600.         LineTo(5,1);°dONLNdÂÂ∏*
  6601.          RGBForeColor(&twoColor);°dONLNdÔ˙|*
  6602.         MoveTo(6,1);°dONLNd˘|*
  6603.         LineTo(7,1);°dONLNd0|*
  6604.         MoveTo(0,2);°dONLNdE
  6605. |*
  6606.         LineTo(7,2);°dONLNdZ"Ω*
  6607. !        SetRect(&localR,0,0,8,3);°dONLNd|!,|*
  6608.         rr = localR;°dONLNdë+6˘*
  6609. -        p = OpenPicture(&(GgwPtr->portRect));°dONLNdø5@Æ*
  6610.         /* first no packing */°dONLNdfi?J*
  6611. 2        (*(GgwPtr -> portPixMap)) -> packType = 1;°dONLNdITÖ*
  6612. I            CopyBits((*(GgwPtr -> portPixMap)),(*(GgwPtr -> portPixMap)),°dONLNd[S^Â*
  6613. )                &rr,&localR,srcCopy,nil);°dONLNdÖ]h*
  6614. 0        /* second pack 2: remove alpha chanel */°dONLNd∂grÃ*
  6615. $            OffsetRect(&localR,0,3);°dONLNd€q|*
  6616. 2        (*(GgwPtr -> portPixMap)) -> packType = 2;°dONLNd{ÜÖ*
  6617. I            CopyBits((*(GgwPtr -> portPixMap)),(*(GgwPtr -> portPixMap)),°dONLNdXÖêÂ*
  6618. )                &rr,&localR,srcCopy,nil);°dONLNdÇèö:*
  6619. :        /* third pack 4: packing component by component */°dONLNdΩô§Ã*
  6620. $            OffsetRect(&localR,0,3);°dONLNd‚£Æ*
  6621. 2        (*(GgwPtr -> portPixMap)) -> packType = 4;°dONLNd≠∏Ö*
  6622. I            CopyBits((*(GgwPtr -> portPixMap)),(*(GgwPtr -> portPixMap)),°dONLNd_∑¬Â*
  6623. )                &rr,&localR,srcCopy,nil);°dONLNdâ¡ÃÄ*
  6624. H        /* The last case is pack 4 but storing the alpha channel also */°dONLNd“À÷Ã*
  6625. $            OffsetRect(&localR,0,3);°dONLNd˜’‡*
  6626. 2        (*(GgwPtr -> portPixMap)) -> packType = 4;°dONLNd*flÍ*
  6627. 2        (*(GgwPtr -> portPixMap)) -> cmpCount = 4;°dONLNd]ÈÙÖ*
  6628. I            CopyBits((*(GgwPtr -> portPixMap)),(*(GgwPtr -> portPixMap)),°dONLNdßÛ˛Â*
  6629. )                &rr,&localR,srcCopy,nil);°dONLNd—˝ã*
  6630.         ClosePicture();°dONLNdÈ€*
  6631. '    UnlockPixels(GgwPtr -> portPixMap);°dONLNd1*
  6632.     }
  6633. °dONLNd'39*X-Ref:°dONLNd3?* ,“Color QuickDraw,” Inside Macintosh Volume V°dONLNdK?K* -“Color QuickDraw,” Inside Macintosh Volume VI°dONLNdyKWå* EMacintosh Technical Note “Things You Wanted To Know about _PackBits…”
  6634. °dONLNdøo~ú*'3BitMapToRgn for nonColor QuickDraw Macintosh models
  6635. °dONLNdÛ~ä>* Written:°dONLNd¸~däà)L11/9/90°dONLNdäñ](≤6Last reviewed:°dONLNdädñà)L2/20/91 ◊4◊˘
  6636. (Ï66) of 29(ÏîColor QuickDraw Q&Asˇ`◊#ˇ ˇˇˇˇ#◊ 
  6637. IR,Times
  6638. .+Z-Developer Support Center(-Ê October 1992 /X/
  6639. °dONLNd<)H(EZIs °dONLNdH)˛) S_BitmapToRegion available on any pre-System7 nonColor QuickDraw configurations such°dONLNdW)<5ˆ(QZ'as the Macintosh Classic, Plus, or SE? °dONLNd~)ˆ5˛)∫9If not, is source or a library module available so that I°dONLNd∏5<A(]ZEdon't have to take the time and compatibility risk of rolling my own?°dONLNd˛A<MN* ___°dONLNdY<eƒ*BitMapToRegion works on °dONLNdYƒe˛)à;pre-color Macintosh systems. You can license BitMapToRegion°dONLNdVe<qS(çZfrom°dONLNd[}<â§*    Software Licensing°dONLNdrâ<ï∞*     Apple Computer, Inc.°dONLNdãï<°“*     20525 Mariani Ave. MS:38-I°dONLNd™°<≠≤*     Cupertino, CA  95014°dONLNd√≠<π«*     AppleLink: SW.LICENSE°dONLNd›π<≈¥*     Phone:(408) 974-4667
  6640. °dONLNdˆ›<Ïó*'0Macintosh QuickDraw pixel map stack requirements
  6641. °dONLNd'Ï<¯b* Written:°dONLNd0Ï௨)L12/3/90°dONLNd8¯<Å( ZLast reviewed:°dONLNdG¯à¨)L5/21/91°dONLNdO<»(8ZWhat are the guidelines for °dONLNdk»˛)å7determining how much of an image CopyBits can copy to a°dONLNd£<(’(DZZMacintosh pixel map at one time, given a particular set of characteristics for the source °dONLNd˝’(˛(DÛmap and°dONLNd(<4(PZAthe destination map and given how much stack space is available? °dONLNdF(4˛(PùFor example, say that we°dONLNd_4<@x(\Z?have an 8-bit-deep pixMap to be copied to a 32-bit-deep pixMap °dONLNdû4x@˛(\ñusing the ditherCopy mode°dONLNd∏@<Lå(hZand expanded by°dONLNd»L<X* .a factor of 4, and we have 45K of stack space.°dONLNd˜X<dN* ___°dONLNd˚p<|Ù*XCopyBits’ stack requirement depends on the width of each scan line (rowBytes). The rule °dONLNdSpÙ|˛(òof°dONLNdV|<à˜(§Z(thumb is that you need at least as much °dONLNd~|˜à˛)ª4stack as the rowBytes value in your image (which can°dONLNd≥à<î¸(∞Z%be huge with 32-Bit QuickDraw), with °dONLNdÿà¸î˛)¿5the following additional modifiers: add an additional°dONLNdî<†Ê(ºZ[rowBytes for dithering; add an additional rowBytes for any stretching (source rect != dest °dONLNdiîʆ˛(ºrect);°dONLNdp†<¨ß(»ZIadd an additional rowBytes for any color map changing; add an additional °dONLNdπ†ß¨˛(»≈rowBytes for any°dONLNd ¨<∏(‘Z,color aliasing. The stack space you need is °dONLNdˆ¨∏˛)Ã1roughly five times the rowBytes of your image. In°dONLNd(∏<ƒá(‡ZDgeneral, you’re better off processing narrower scan lines. Reducing °dONLNdl∏áƒ˛(‡•the vertical size will not°dONLNdáƒ<–0(ÏZ2affect stack requirements. Narrow, tall bands (if °dONLNdπƒ0–˛)Ù'you can use them) will reduce the stack°dONLNd·–<‹}(¯Z
  6642. requirements.
  6643. °dONLNdÔÙ<ª*'6Color and nonColor QuickDraw trap dispatch differences
  6644. °dONLNd&<b* Written:°dONLNd/à¨)L1/28/91°dONLNd7<Å(7ZLast reviewed:°dONLNdFà¨)L2/13/91°dONLNdN'<3‰(OZRWhy does a call to RGBForeColor cause a corruption of the stack without resulting °dONLNd†'‰3˛(Oin an°dONLNd¶3<?ç([ZAunimplemented trap error on nonColor QuickDraw Macintosh systems?°dONLNdË?<KN* ___°dONLNdÏW<cQ*The °dONLNdWQc˛)Ttrap dispatcher on Color QuickDraw and nonColor QuickDraw machines are different. If°dONLNdEc<o%(ãZ/you look at page 89 of Inside Macintosh Volume °dONLNdtc%o˛)È-I, you’ll see the toolbox trap word format as°dONLNd¢o<{π(óZJit was in the days before Color QuickDraw. Bit 9 was “reserved for future °dONLNdÏoπ{˛(ó◊ use” and was°dONLNd˘{<áò(£Zignored by the trap °dONLNd    
  6645. {òá˛)\Jdispatcher, and so it was normally set to 0. That means that valid toolbox°dONLNd    Xá<ì¡(ØZtraps could either look like °dONLNd    uá¡ì˛)Ö:$A8XX or $A9XX as long as the auto-pop bit was turned off.°dONLNd    ∞ì<ü?(ªZ5Color QuickDraw machines have a trap dispatcher that °dONLNd    Âì?ü˛(ª](uses that reserved bit to allow for more ◊X◊
  6646. (ÏZColor QuickDraw Q&As(Ïˇ7) of 29ˇ◊#ˇ ˇˇˇˇ#◊ 
  6647. IR,Times
  6648. .+6-Macintosh Technical Notes /4/˘
  6649. °dONLNd)*4trap words, and therefore it has a much larger trap °dONLNd4)⁄)Ô*dispatch table. Color QuickDraw traps have°dONLNd_)5N(Q6?that reserved bit set, so those traps look like $AAXX or $ABXX.°dONLNdüAM•*SWhen a nonColor QuickDraw machine tests to see if a trap is implemented or not, it °dONLNdÚA•M⁄(i√ just checks°dONLNd˛MY^(u6Dthe trap dispatch table to see if a routine is implemented for that °dONLNdBM^Y⁄(u|trap or not. Because the°dONLNd[Ye](Å6reserved bit is °dONLNdkY]e⁄)EKignored, trap words that look like $AAXX are treated as equivalent to $A8XX°dONLNd∑eqb(ç6and trap words °dONLNdΔebq⁄)JJthat look like $ABXX are treated as equivalent to $A9XX. The trap word for°dONLNdq}Ø(ô6HRGBForeColor is $AA14. If you call RGBForeColor on a nonColor QuickDraw °dONLNdYqØ}⁄(ôÕmachine,°dONLNdb}â(•6-$AA14 is treated as $A814, which is the trap °dONLNdè}â⁄)È*word for SetFractEnable. SetFractEnable is°dONLNd∫âïæ(±6Simplemented on 128K ROM machines or greater, so no unimplemented trap error occurs.°dONLNd°≠_*If you look at °dONLNd°_≠⁄)GKrecent DTS sample programs, such as the Utilities sample (SC.025.Utilities,°dONLNdi≠πä(’6which you can find on °dONLNd≠äπ⁄)r@AppleLink in Developer Support and on the current developer CD),°dONLNd¿π≈◊(·6+you’ll see a routine in Utilities.c called °dONLNdÎπ◊≈⁄)ø6TrapExists. It takes into account the size of the trap°dONLNd"≈—I(Ì6Edispatch table so that you can tell in one call whether a routine is °dONLNdg≈I—⁄(Ìgimplemented or not regardless°dONLNdÖ—›Ü(˘6Mof whether it’s a Color QuickDraw trap or not and regardless of what kind of °dONLNd“—Ü›⁄(˘§Macintosh you’re°dONLNd„›ÈP(6 running on.°dONLNdÔıa*CUnder system software version 7.0, the trap dispatcher is modified °dONLNd2ıa⁄(on nonColor QuickDraw°dONLNdH
  6650. Ü()6machines so that many °dONLNd^Ü
  6651. ⁄)nBColor QuickDraw traps are implemented and work as well as they can°dONLNd°
  6652. r(56in black and white.
  6653. °dONLNdµ1@U*'-Macintosh OpenCPicture 72 dpi calculation bug
  6654. °dONLNd„@L>* Written:°dONLNdÏ@dLà)L2/12/91°dONLNdÙLX](t6Last reviewed:°dONLNdLdXà)L2/20/91°dONLNd dpá(å6The 32-Bit QuickDraw °dONLNd dáp⁄)oG_OpenCPicture call incorrectly calculates the 72 dpi frame width if the°dONLNdhp|g(ò6Bheight of the native resolution srcRect exceeds 910 dots. To work °dONLNd™pg|⁄(òÖaround this problem, I°dONLNd¡|àG(§6
  6655. calculate °dONLNdÀ|Gà⁄)/Ithe 72 dpi frame independently, and store it in the PicHandle returned by°dONLNdàîd(∞6_OpenCPicture.°dONLNd$î†** ___°dONLNd(¨∏Ä*It’s a known bug that °dONLNd>¨Ä∏⁄)hBunder Macintosh Systems 6.0.5 and 6.0.7 with 32-Bit QuickDraw 1.2,°dONLNdÅ∏ƒx(‡6GOpenCPicture doesn’t properly calculate the right coordinate of the 72 °dONLNd»∏xƒ⁄(‡ñdpi picFrame if the°dONLNd‹ƒ–E(Ï6
  6656. height of °dONLNdʃE–⁄)-Rthe srcRect (native resolution rectangle) multiplied by 72 exceeds $0000FFFF. That°dONLNd9–‹ˆ(¯6-works out to a maximum height of 910 pixels, °dONLNdf–ˆ‹⁄)fi.just as you found. This bug is fixed in System°dONLNdï‹Ëâ(6H7.0, but gestaltQuickDrawVersion returns $0220 both under Systems 6.0.5 °dONLNd›‹âË⁄(ßand 7.0, so you°dONLNdÌËÙÕ(6$can’t tell whether the bug is fixed °dONLNd    ËÕÙ⁄)µ2that way. Instead, you should use Gestalt with the°dONLNd    DÙ(68gestaltSystemVersion selector. If the returned value is °dONLNd    |Ù⁄(7'$0700 or greater, then let OpenCPicture°dONLNd    § õ((6Rhandle the picFrame calculation; otherwise you should do the calculation yourself.
  6657. °dONLNd    ˜$3$*'"GetGWorldPixMap bug and workaround
  6658. °dONLNd
  6659. 3?>* Written:°dONLNd
  6660. #3d?à)L3/12/91°dONLNd
  6661. +?K](g6Last reviewed:°dONLNd
  6662. :?dKà)L10/9/91°dONLNd
  6663. BWcÔ(6&Why does GetGWorldPixMap (when called °dONLNd
  6664. hWÔc⁄)◊.on a Macintosh II, IIcx, or IIx running system°dONLNd
  6665. ócoº(ã6Wsoftware version 6.0.5 or 6.0.7 with 32-Bit QuickDraw 1.2) return a combination of the °dONLNd
  6666. Ócºo⁄(ã⁄device°dONLNd
  6667. ıo{ä(ó6Qfield (two bytes) and the first two bytes of the portPixMap field? Is this a bug?°dONLNd G{á** ___ ◊4◊˘
  6668. *I8) of 29(ÏîColor QuickDraw Q&Asˇ&◊#ˇ ˇˇˇˇ#◊ 
  6669. IR,Times
  6670. .+Z-Developer Support Center(-Ê October 1992 /X/
  6671. °dONLNd<)ì(EZYour analysis of °dONLNdì)˛)WEGetGWorldPixMap is exactly right: It doesn’t work correctly in system°dONLNdW)<5√(QZsoftware version 6.0.5 and °dONLNdr)√5˛)á>6.0.7 with 32-Bit QuickDraw 1.2. It returns a value that’s two°dONLNd±5<A(]Z/bytes before the value it’s supposed to return.°dONLNd·M<YÖ*The solution is °dONLNdÒMÖY˛)IHto use GWorldPtr->portPixMap instead of GetGWorldPixMap. It’s safe to do°dONLNd:Y<e/(ÅZ/this, but you should use GetGWorldPixMap under °dONLNdiY/e˛)Û*System 7. Not only is the bug fixed there,°dONLNdîe<qD(çZ7but dereferencing the port is dangerous under System 7 °dONLNdÀeDq˛(çb$because it may not be CGrafPort. Use°dONLNdq<}T(ôZ5Gestalt with the gestaltQuickdrawVersion selector to °dONLNd%qT}˛(ôrdetermine whether you can use°dONLNdC}<â(•Z&GetGWorldPixMap. If Gestalt returns a °dONLNdi}â˛)›(value from gestalt8BitQD ($0100) through°dONLNdíâ<ïC(±Z/gestalt32BitQD12 ($0220), then GetGWorldPixMap °dONLNd¡âCï˛(±a$either doesn’t exist or is the buggy°dONLNdÊï<°z(ΩZversion. If it °dONLNdıïz°˛)>Kreturns gestalt32BitQD13 ($0230) or higher, then GetGWorldPixMap does exist°dONLNdA°<≠M(…Z4and works correctly. Interestingly, GetGWorldPixMap °dONLNdu°M≠˛(…k"can be called on a black-and-white°dONLNdò≠<πH(’Z6QuickDraw machine under System 7. It returns a handle °dONLNdŒ≠Hπ˛(’f&to a structure which should be treated°dONLNdıπ<≈z(·Z as a BitMap °dONLNdπz≈˛)>Lstructure, though there are some undocumented fields after the normal BitMap°dONLNdN≈<—≥(ÌZfields. To tell whether °dONLNdf≈≥—˛)w;GetGWorldPixMap is available on a black-and-white QuickDraw°dONLNd¢—<›®(˘Zmachine, you must °dONLNd¥—®›˛)l=check the system software version by calling Gestalt with the°dONLNdÚ›<È(ZZgestaltSystemVersion selector. Ifit returns $0700 or higher, GetGWorldPixMap is available.
  6672. °dONLNdM<k*'(System 7 TextMode problem and workaround
  6673. °dONLNdv<b* Written:°dONLNdà¨)L6/12/91°dONLNdá<(Å(DZLast reviewed:°dONLNdñà(¨)L8/13/91°dONLNdû4<@É(\ZBOur application uses the TextMode (blend + mask) as documented in °dONLNd‡4É@˛(\°Inside Macintosh Volume°dONLNd¯@<LÕ(hZVV (blend is equal to the current ditherCopy constant) to make translucent text. Under °dONLNdN@ÕL˛(hΠ   System 7,°dONLNdXL<Xä(tZDthis transfer mode causes garbage to appear when the text is drawn. °dONLNdúLäX˛(t®Is there a way to work°dONLNd≥X<d˘(ÄZ(around the problem? Will there be a fix?°dONLNd‹d<pN* ___°dONLNd‡|<àQ*The °dONLNd‰|Qà˛)Uproblem you are seeing is due to the use of CopyDeepMask instead of the old-fashioned°dONLNd:à<î5(∞Z5CopyBits to do the job. It is being studied now, and °dONLNdoà5î˛)˘+the hope is that it will work as advertised°dONLNdõî<†Ù(ºZ'in a future release. One workaround is °dONLNd¬îÙ†˛)∏8to render the text to an off-screen pixmap and then call°dONLNd˚†<¨X(»Z=CopyBits (using blendMode) to actually put it in the picture.
  6674. °dONLNd9ƒ<”Õ*'9Using dithering and animation on the same Macintosh image
  6675. °dONLNds”<flb* Written:°dONLNd|”àfl¨)L6/19/91°dONLNdÑfl<ÎÅ(ZLast reviewed:°dONLNdìflàÎ≤)L10/15/91°dONLNdú˜<T(Z:When setting up a dithered grayscale image for subsequent °dONLNd÷˜T˛(r$animation (to adjust brightness, for°dONLNd˚<n(+Z
  6676. example), °dONLNd    n˛)2Ra conflict arises between the use of Palette animation and the ditherCopy CopyBits°dONLNd    X<¥(7ZGmode.This problem is demonstrated in the develop #5 GiMeDaPalette code °dONLNd    ü¥˛(7“sample: If you°dONLNd    Æ<'K(CZ3change srcCopy to ditherCopy in the CopyBits call, °dONLNd    ·K'˛(Ci!then run the program and selected°dONLNd
  6677. '<3w(OZ@Animate, the resulting image is pure black and white, with what °dONLNd
  6678. C'w3˛(Oïappears to be an attempt to°dONLNd
  6679. _3<?Á([Z_dither with just the black and white color table entries (that are not reserved for animation).°dONLNd
  6680. øK<W%*1This happens because ditherCopy tries to use the °dONLNd
  6681. K%W˛)È,inverse table to do color matching, but when°dONLNd W<cπ(ZTthe image is animated, the inverse table colors are limited to just black and white.°dONLNd ro<{L*To °dONLNd uoL{˛)Twork around the problem, you can jump into the bottlenecks and when you see the PICT°dONLNd  {<á§(£Zhitting the opcode for °dONLNd ·{§á˛)hBCopyBits, change the PICT from a srcCopy to a ditherCopy. This way°dONLNd $á<ì≈(ØZthe dithering happens when °dONLNd ?á≈ì˛)â>you do the call to DrawPicture and not later on. This makes it°dONLNd ~ì<üR(ªZ:possible to use dithering and animation on the same image. ◊X◊
  6682. *1Color QuickDraw Q&As(Ïˇ9) of 29ˇ@◊#ˇ ˇˇˇˇ#◊ 
  6683. IR,Times
  6684. .+6-Macintosh Technical Notes /4/˘
  6685. °dONLNd)8ó*'6Rendering color PICTs in a black-and-white environment
  6686. °dONLNd78D>* Written:°dONLNd@8dDà)L7/22/91°dONLNdHDP](l6Last reviewed:°dONLNdWDdPà)L9/17/91°dONLNd_\h¢(Ñ6QI want to be able to render a color PICT as a black-and-white image substituting °dONLNd∞\¢h⁄(Ñ¿ patterns for°dONLNdΩhtà(ê6colors. My images are °dONLNd”hàt⁄)pApretty small and have under 16 colors. What do you suggest as the°dONLNdtÄS(ú6 easiest way?°dONLNd"Äå** ___°dONLNd&ò§Í*,One easy way is to take advantage of 32-Bit °dONLNdRòͧ⁄)“.QuickDraw and System 7.0’s ditherCopy transfer°dONLNdŧ∞‡(Ã6%mode modifier or flag (documented in °dONLNd¶§‡∞⁄)»-Inside Macintosh Volume VI, page 17-17). Call°dONLNd‘∞º (ÿ6[DrawPicture into an offscreen pixmap with the pixel depth of the original color PICT. Then °dONLNd/∞ º⁄(ÿËcall°dONLNd4º»(‰6CopyBits to copy the °dONLNdIº»⁄)gEpixmap to the screen, with srcCopy + ditherCopy as the transfer mode.°dONLNd軑a(6GThis will result in a nicely dithered image on the black-and-white end.°dONLNd◊‡Ïê*KUnder System 6 without 32-Bit QuickDraw, the solution is not nearly so cut °dONLNd"‡êÏ⁄(Æand dried. One°dONLNd1ϯI(6<way might be to take advantage of the fact that DrawPicture °dONLNdmÏI¯⁄(ggoes through the QuickDraw°dONLNdà¯≈( 6"bottlenecks for drawing. For each °dONLNd™¯≈⁄)≠5grafproc in your PICT, you'd intercept StdBits during°dONLNd‡∫(,6TDrawPicture and call your own dithering routine to examine the foreground color and °dONLNd4∫⁄(,ÿset the°dONLNd<§(86Zpen pattern or fill pattern so that it has about the same lightness as the original color.°dONLNdó(4{*LWell, this came out as a great sales pitch for writing a System 7-savvy app!
  6687. °dONLNd‰L[¥*';Highlighting ignored if foreground same as background color
  6688. °dONLNd [g>* Written:°dONLNd)[dgÇ)L8/7/91°dONLNd0gs](è6Last reviewed:°dONLNd?gdsà)L9/24/91°dONLNdGãB(ß6>Under System 7, but not System 6, HiliteColor is not used for °dONLNdÖBã⁄(ß`!InvertRect when the hilite bit is°dONLNdßãó>(≥67set and the background is exactly black (R=G=B=$0000). °dONLNdfiã>ó⁄(≥\Also, HiliteColor doesn’t draw°dONLNd˝ó£(ø60when a pen mode of XOR is used in a LineTo call.°dONLNd.£Ø** ___°dONLNd2ª«∞*RThe problem you encounter exists whenever the background and foreground color are °dONLNdѪ∞«⁄(„Œthe same°dONLNdç«”\(Ô6?when using highlight mode. If the foreground color is the same °dONLNdë\”⁄(Ôzas the background color,°dONLNd”flq(˚6Ihighlighting is ignored. Therefore, when you set the foreground color to °dONLNd.”qfl⁄(˚èwhite, you should set°dONLNdDflÎk(6Hthe background color to something other than the default color of white.
  6689. °dONLNdç>*'*Gestalt 'qdrw' selector bug and workaround
  6690. °dONLNd∏>* Written:°dONLNd¡dÇ)L8/1/91°dONLNd»*](F6Last reviewed:°dONLNd◊d*à)L10/9/91°dONLNdfl6B`(^6<Why does Gestalt tell me I have Color QuickDraw features on °dONLNd6`B⁄(^~a non-Color QuickDraw°dONLNd1BND(j6machine?°dONLNd:NZ** ___°dONLNd>frè*JThe gestaltQuickdrawFeatures ('qdrw') selector, used for determining your °dONLNdàfèr⁄(é≠system’s Color°dONLNdór~î(ö6SQuickDraw features, has a bug that causes it to tell you incorrectly that noncolor °dONLNdÍrî~⁄(ö≤
  6691. machines have°dONLNd¯~ä7(¶6color. °dONLNdˇ~7ä⁄)XThe fix is quite simple: Gestalt has another selector, gestaltQuickdrawVersion ('qd  '),°dONLNd    Xäñ2(≤68which simply returns the QuickDraw version number. This °dONLNd    êä2ñ⁄(≤P!version number is < gestalt8BitQD°dONLNd    ≤ñ¢†(æ6for classic QuickDraw and °dONLNd    Ãñ†¢⁄)à:>= gestalt8BitQD for Color QuickDraw (see Inside Macintosh ◊4◊˘
  6692. (Ï610)
  6693.  of 29(ÏîColor QuickDraw Q&Asˇ`◊#ˇ ˇˇˇˇ#◊ 
  6694. IR,Times
  6695. .+Z-Developer Support Center(-Ê October 1992 /X/
  6696. °dONLNd<)µ(EZMVolume VI, page 3-39, for more information). The trick is to ask Gestalt for °dONLNdMµ)˛(E”
  6697. the QuickDraw°dONLNd[)<5Õ(QZPversion first; once you’ve determined that you have Color QuickDraw, the 'qdrw' °dONLNd´)Õ5˛(QÎ selector is°dONLNd∑5<A–(]Z OK to use to find out specifics.
  6698. °dONLNdÿY<hä*'-Version 2 PICTs on pre-Color QuickDraw models
  6699. °dONLNdh<tb* Written:°dONLNdhàt¨)L8/13/91°dONLNdt<ÄÅ(úZLast reviewed:°dONLNd&tàÄ≤)L10/22/91°dONLNd/å<ò€(¥ZInside Macintosh Volume V says °dONLNdNå€ò˛)ü;a System 4.1 (and later) patch ensures that version 2 PICTs°dONLNdäò<§G(¿Z7are displayed correctly on earlier machines that don’t °dONLNd¡òG§˛(¿e!have Color QuickDraw, such as the°dONLNd„§<∞ç(ÃZ>Macintosh Plus and SE. However, my version 2 PICT, consisting °dONLNd!§ç∞˛(ôprimarily of a PixMap°dONLNd7∞<ºG(ÿZ7(opcode = $90 since rowbytes <8) displays correctly on °dONLNdn∞Gº˛(ÿe%a Macintosh IIfx but displays garbage°dONLNdîº<»ô(‰Zon a Macintosh SE.°dONLNdß»<‘N* ___°dONLNd´‡<Ï*+The PICT problem you reported is caused by °dONLNd÷‡Ï˛)ÿ,a bug in 6.0.7 QuickDraw. The workaround for°dONLNdÏ<¯ò(Zthe time being is to:°dONLNd<
  6700. *+• Use System 7.0, where it’s been fixed, or°dONLNdE<s* @• Don’t use opcode $90. Instead, use padding so that opcode $98 °dONLNdÖs˛(8ëcan be used. (Opcode $98 is°dONLNd°<(M(DZthe °dONLNd•M(˛)Wpacked copybits version that works for rowbytes >= 8.). You can do this by creating the°dONLNd˝(<4‚(PZ#picture with a PixMap that’s wider °dONLNd (‚4˛)¶<than you actually need, and then use the clip region to clip°dONLNd]4<@ø(\Zout the part you don’t need.
  6701. °dONLNdzX<g*' GetPixelsState is slow sometimes
  6702. °dONLNdõg<sb* Written:°dONLNd§gàs¨)L8/27/91°dONLNd¨s<Å(õZLast reviewed:°dONLNdªsà¨)L9/24/91°dONLNd√ã<ó‰(≥ZJWhy do I sometimes see incredible slowdowns under System 7.0 when calling °dONLNd
  6703. ã‰ó˛(≥either°dONLNdó<£W(øZ6GetPixelsState or LockPixels (I’m not sure which) for °dONLNdJóW£˛(øuthe PixMapHandle of a GWorld°dONLNdg£<Ø”(ÀZallocated in temporary memory?°dONLNdÜØ<ªN* ___°dONLNdä«<”˛*)GetPixelsState takes an arbitrary amount °dONLNd≥«˛”˛)¬5of time since it makes a call to RecoverHandle to get°dONLNdÈ”<flÓ(˚Z\the handle pointing to the baseaddr. Therefore, the slowdown you see as actually due to the °dONLNdE”Ófl˛(˚ call°dONLNdJfl<Ω(ZJto RecoverHandle, which is slow because it must traverse the heap to find °dONLNdîfl©Î˛(«the pointer to the°dONLNdßÎ<˜ú(ZIbaseaddr. LockPixels is not responsible for the slowdown because it does °dONLNdÎú˜˛(∫not make call to any°dONLNd˜</(Z2traps which could take an extended amount of time.
  6704. °dONLNd8<*Z*'(OpenCPicture and PICTs other than 72 dpi
  6705. °dONLNda*<6b* Written:°dONLNdj*à6¨)L10/2/91°dONLNdr6<BÅ(^ZLast reviewed:°dONLNdÅ6àB¨)L10/8/91°dONLNdâN<ZÚ(vZ\Can I use OpenCPicture to create PICTs with a higher resolution than 72 dots per inch (dpi)?°dONLNdÊZ<fH* __°dONLNdÈr<~n*=There’s good news and bad news: The good news is that you’re °dONLNd&rn~˛(öåon top of the situation, which°dONLNdE~<äI(¶Z:means the bad news is that there aren’t better ways to do °dONLNd~Iä˛(¶g#what you want to do, mostly. Here’s°dONLNd£ä<ñl(≤Z
  6706. the scoop: ◊X◊
  6707. *:Color QuickDraw Q&As(Ï˙11)
  6708.  of 29ˇ(◊#ˇ ˇˇˇˇ#◊ 
  6709. IR,Times
  6710. .+6-Macintosh Technical Notes /4/˘
  6711. °dONLNd)*2You can use vRes and hRes in pictures opened with °dONLNd2)⁄)¯)OpenCPicture to tell QuickDraw it’s not a°dONLNd\)5—(Q6Z72-dpi picture, and as long as the application that receives the picture uses DrawPicture °dONLNd∂)—5⁄(QÔto°dONLNdπ5Aw(]6Eimage it, QuickDraw will Do The Right Thing—scaling it on the screen °dONLNd˛5wA⁄(]ïto 72 dpi instead of°dONLNdAM’(i6[making it humongously large. Unfortunately, this way you lose hairlines; if you print such °dONLNdnA’M⁄(iÛa°dONLNdpMY≤(u6#picture to a 72 dpi grafPort (like °dONLNdìM≤Y⁄)ö>the LaserWriter driver normally returns), you’ll get 1/72-inch°dONLNd“Ye(Å67lines instead of 1/300-inch lines as you probably want.°dONLNd
  6712. q}o*H(This _can_ work correctly, but the receiving application has to notice °dONLNdRqo}⁄(ôçyour picture is bigger°dONLNdi}â/(•6than °dONLNdn}/â⁄)Y72 dpi and ask PrGeneral to increase the resolution of the printing grafPort accordingly,°dONLNd»âï‹(±6)and this doesn’t always or often happen.)
  6713. °dONLNdÚ≠ºQ*'+No System 7 QuickDraw alpha channel support
  6714. °dONLNdº»>* Written:°dONLNd'ºd»é)L10/23/91°dONLNd0»‘](6Last reviewed:°dONLNd?»d‘é)L11/27/91°dONLNdH‡Ï6(6:How can I directly access the alpha channel (the unused 8 °dONLNdLJ6Ï⁄(T#bits in a 32-bit direct pixel using°dONLNd¶Ï¯ô(6QuickDraw) under System °dONLNdæÏô¯⁄)Å>7? Under System 6 it was easy, but under System 7’s CopyBits()°dONLNd˝¯1( 69the alpha channel works with srcXor but not with srcCopy.°dONLNd7** ___°dONLNd;(Ö*HWith the System 7.0 QuickDraw rewrite, all “accidental” support for the °dONLNdÉÖ(⁄(D£unused byte was°dONLNdì(4À(P6"removed, because QuickDraw is not °dONLNdµ(À4⁄)≥5supposed to operate on the unused byte of each pixel.°dONLNdÎ4@Å(\6QuickDraw has never °dONLNdˇ4Å@⁄)iHofficially supported use of the extra byte for such purposes as an alpha°dONLNdH@L˘(h6.channel. As stated in Inside Macintosh Volume °dONLNdv@˘L⁄)·0VI, page 17-5, “8 bits in the pixel are not part°dONLNdßLXæ(t6!of any component. These bits are °dONLNd»LæX⁄)¶6unused: Color QuickDraw sets them to 0 in any image it°dONLNdˇXdª(Ä6Tcreates. If presented with a 32-bit image—for example, in the Copybits procedure—it °dONLNdSXªd⁄(ÄŸpasses°dONLNdZdpã(å6whatever bits are there.”°dONLNdt|à¶*RTherefore, you cannot rely on any QuickDraw procedure to preserve the contents of °dONLNdΔ|¶à⁄(§ƒ
  6715. the unused°dONLNd—àîî(∞6byte, which in your case °dONLNdÍàîî⁄)|Bis the alpha channel. In fact, even CopyBits may alter the byte if°dONLNd-î†é(º6stretching or dithering is °dONLNdHîé†⁄)vEinvolved in the copybits by setting them to zero. Therefore, the only°dONLNd醨s(»6Ipossible workarounds for this problem are to not use the unused byte for °dONLNd◊†s¨⁄(»ëalpha channel storage°dONLNd̨∏((‘6=since the integrity of the data cannot be guaranteed; or, to °dONLNd*¨(∏⁄(‘F"not use QuickDraw drawing routines°dONLNdM∏ƒ∞(‡6 which can alter the unused byte.
  6716. °dONLNdn‹Î7*'$BitsToRgn and MPW BitMapToRegionGlue
  6717. °dONLNdìΘ>* Written:°dONLNdúÎd˜é)L10/29/91°dONLNd•˜](6Last reviewed:°dONLNd¥˜dé)L12/11/91°dONLNdΩÊ(76%Which version of the system software °dONLNd‚Ê⁄)Œ.first contained the call BitsToRgn? Is there a°dONLNd    'ë(C6Pworkaround for this call if my users have an earlier version of system software?°dONLNd    b'3** ___°dONLNd    f?K2*The °dONLNd    j?2K⁄)Icall BitmapToRegion was introduced with 32-bit QuickDraw and became fully°dONLNd    ¥KW9(s66documented in Volume VI of Inside Macintosh, which is °dONLNd    ÍK9W⁄(sWprimarily System 7 information.°dONLNd
  6718.  
  6719. Wcê(6GHowever, since the differences between System 7’s QuickDraw and 32-bit °dONLNd
  6720. QWêc⁄(Æ
  6721. QuickDraw are°dONLNd
  6722. _co§(ã6minor, most of System 7’s °dONLNd
  6723. yc§o⁄)å<QuickDraw routines are available in system software prior to°dONLNd
  6724. ∂o{Î(ó6+System 7.0 using the 32-bit QuickDraw Init.°dONLNd
  6725. ‚áìF*    To check °dONLNd
  6726. ÎáFì⁄).Rto see if a system contains 32-bit QuickDraw, you can use the following snippet of°dONLNd >ìü1(ª6code: ◊4◊˘
  6727. *112)
  6728.  of 29(ÏîColor QuickDraw Q&Asˇ‡◊#ˇ ˇˇˇˇ#◊ 
  6729. IR,Times
  6730. .+Z-Developer Support Center(-Ê October 1992 /X/,
  6731. Courier
  6732.     °dONLNd<(ï(DZE    /* Find out if GWorlds and CQD are implemented on this machine */°dONLNdF'<2r*
  6733. >    (void) Gestalt (gestaltQuickdrawVersion, /*<*/&qdVersion);°dONLNdÖ1<<;*
  6734. 3    gHasGWorlds = (qdVersion > gestaltOriginalQD &&°dONLNd∫;<F*
  6735. -                   qdVersion < gestalt8BitQD)°dONLNdËE<P1*
  6736. 1                  || qdVersion >= gestalt32BitQD;
  6737. °dONLNd[<g√*OIf you are using MPW as a development platform, MPW has a library call you can °dONLNdi[√g˛(É·
  6738. use that will°dONLNdwg<sØ(èZKallow you to use the routine regardless of whether or not 32-bit QuickDraw °dONLNd¬gØs˛(èÕexists. The glue°dONLNd”s<s(õZ?routine is called BitMapToRegionGlue() and is available to MPW °dONLNdss˛(õëusers. Substitute this call for°dONLNd2<ã(ßZ,BitMapToRegion calls and the glue code will °dONLNd^ã˛)◊2take care of patching in the proper code if 32-bit°dONLNdëã<ó†(≥ZQuickDraw does not °dONLNd§ã†ó˛)dHexist. If you’re using Think C, you can use the oConv utility to convert°dONLNdÌó<£((øZ1the MPW object file into a Think C usable format.
  6739. °dONLNdª< f*'+Ensuring even rowBytes for 'cicn' resources
  6740. °dONLNdK <÷b* Written:°dONLNdT à÷¨)L12/4/91°dONLNd\÷<‚Å(˛ZLast reviewed:°dONLNdk÷à‚¨)L1/27/92°dONLNdsÓ<˙∂(ZPIs there any way to force bitmaps and masks within a 'cicn' resource to have an °dONLNd√Ó∂˙˛(‘
  6741. even rowBytes°dONLNd—˙<&("Z2(using ResEdit)? I want to avoid duplicating icon °dONLNd˙&˛)Í(bitmaps—one for color systems set to B&W°dONLNd,<P(.Zand °dONLNd0P˛)Qone for B&W systems—to reduce program size as well as development and maintenance°dONLNdÇ<œ(:ZYcosts. The bitmaps in the 'cicn' can also be sized specifically to the task, whereas the °dONLNd€œ˛(:Ìold B&W°dONLNd„<*¥(FZicons are of a fixed size °dONLNd˝¥*˛)xBand contain no sizing information. It’s simple enough to read in a°dONLNd@*<6È(RZ#'cicn' and extract the bitmap. The °dONLNdc*È6˛)≠3problem is that on a 68000 (no Color QuickDraw), if°dONLNdó6<B(^Z-rowBytes is odd, an odd address trap results.°dONLNd≈B<NN* ___°dONLNd…Z<f≥*OThere isn’t any way to get ResEdit itself to create BitMaps with even rowBytes °dONLNdZ≥f˛(Ç—for 8 x 8 'cicn'°dONLNd)f<r˙(éZ(resources, but here are few suggestions:°dONLNdR~<ä*/You could process your 'cicn' resources first, °dONLNdÅ~ä˛)‹.so that they have BitMaps as you require them.°dONLNd∞ä<ñŸ(≤ZUTo alter the resource with a quick little program would be trivial, especially given °dONLNdäŸñ˛(≤˜that the°dONLNdñ<¢(æZ/bitmap data sits last in the 'cicn'. All you’d °dONLNd=ñ¢˛)◊-need to do is expand the bitmap image data by°dONLNdk¢<Æ√( ZQpadding each line to an even length and then changing the rowBytes value. Or you °dONLNdº¢√Æ˛( · could de-rez°dONLNd…Æ<∫-(÷Z6the 'cicn's and patch them with a text editor, either °dONLNdˇÆ-∫˛)Ò+by hand or with a search-and-replace script°dONLNd+∫<Δ~(‚Z
  6742. of some kind.
  6743. °dONLNd9fi<Ì‹*';CopyBits blend mode: OpColor's affect & eliminating banding
  6744. °dONLNduÌ<˘b* Written:°dONLNd~Ìà˘≤)L12/11/91°dONLNdá˘<Å(!ZLast reviewed:°dONLNdñ˘à¨)L2/17/92°dONLNdû<ı(9Z_I have two grey-colored pixmaps that I wish to blend together; one is on the screen, the other °dONLNd˝ı˛(9in°dONLNd    <)Ì(EZ$an offscreen pixmap. I use CopyBits °dONLNd    $Ì)˛)±9to copy the offscreen to the screen, but it does not seem°dONLNd    ^)<5∞(QZQto blend them. Instead, it seems to match the colors of the screen bitmap to the °dONLNd    Ø)∞5˛(QŒclosest colors in°dONLNd    ¡5<AN(]Z:some table, thus having the effect of reducing the number °dONLNd    ˚5NA˛(]l%of colors displayed on the screen bit°dONLNd
  6745. !A<M´(iZmap. Any suggestions?°dONLNd
  6746. 7M<YN* ___°dONLNd
  6747. ;e<qÎ*\There are two distinct questions here: 1) Why ain’t it blending? and 2) What’s this banding °dONLNd
  6748. óeÎq˛(ç    for?°dONLNd
  6749. úq<}»(ôZThe first problem is almost °dONLNd
  6750. ∏q»}˛)å>certainly because OpColor isn’t set properly. This is a third,°dONLNd
  6751. ˜}<â (•Zimplicit, operand on several °dONLNd } â˛)é>arithmetic graphics operations, including blend. For blend, it°dONLNd Sâ<ïø(±ZQdescribes the proportions to mix the source and destination colors in the blend. °dONLNd §âøï˛(±› For an equal°dONLNd ±ï<°ê(ΩZmix, you should °dONLNd ¡ïê°˛)TIset this color to a halfway gray. (Call OpColor() with a color where red,°dONLNd °<≠€(…Z"green, and blue all equal $8000.) °dONLNd -°€≠˛)ü=This effect is described in the description of the blend mode ◊X◊
  6752. (ÏZColor QuickDraw Q&As(Ï˙13)
  6753.  of 29ˇ˛◊#ˇ ˇˇˇˇ#◊ 
  6754. IR,Times
  6755. .+6-Macintosh Technical Notes /4/˘
  6756. °dONLNd)Å*on page 60 of Inside °dONLNdÅ)⁄)iDMacintosh, Volume V. Unfortunately, the initial value for OpColor is°dONLNdZ)5Z(Q6Cblack (0,0,0), so you were seeing no mixing of your offscreen data.°dONLNdûAM~*IThe second half of your question is why you’re getting a banding effect. °dONLNdÁA~M⁄(iú(When you fix the°dONLNd˘MYë(u6Nabove problem, you’ll still get banding.) Unfortunately, the arithmetic modes °dONLNdGMëY⁄(uØare constrained°dONLNdWYeô(Å6Qby the size of the inverse table. As your screen no doubt uses the default 4-bit °dONLNd®Yôe⁄(Å∑inverse table,°dONLNd∑eqå(ç6Nyou’ll find that you’ll get only 2^4 = 16 levels of gray. If you enlarge your °dONLNdeåq⁄(ç™screen’s inverse°dONLNdq}1(ô6>table to 5 bits, the maximum allowable, you’ll still only get °dONLNdTq1}⁄(ôO$32 gray levels. (To do this, set the°dONLNdy}â≥(•6gdResPref field in the GDevice °dONLNdò}≥â÷)õ:to 5, then call MakeITable().) The only way to get a fully°dONLNd“}÷â⁄(•Ù-°dONLNd”âïB(±6    gradual, °dONLNd‹âBï⁄)*Ugreat-looking effect is to do all the work offscreen in 24-bit deep pixmaps, and then°dONLNd2ï°;(Ω6copy it °dONLNd:ï;°⁄)#Vto the screen. Because they can operate directly on colors, rather than having to work°dONLNdë°≠Õ(…6\through the intermediary of color indices, direct pixmaps are not limited by inverse tables °dONLNd̰Õ≠⁄(…Î(in°dONLNdÒ≠πF(’6?fact, they don’t even have real inverse tables). You could use °dONLNd0≠Fπ⁄(’d16-bit pixmaps, but they only°dONLNdNπ≈ÿ(·6)provide 32 grays (having only 5 bits for °dONLNdwπÿ≈⁄)¿4each component), so this wouldn’t be any better than°dONLNd¨≈—Œ(Ì6)increasing the size of the inverse table.
  6757. °dONLNd÷ȯ;*'(Icon dimming under System 7 and System 6
  6758. °dONLNdˇ¯>* Written:°dONLNd¯dÇ)L1/6/92°dONLNd](,6Last reviewed:°dONLNddÇ)L2/6/92°dONLNd%(z(D6FWhen you bring up the Control Panels window under System 7 on a color °dONLNdkz(⁄(Dòsystem and click on°dONLNd(4ö(P6Wa control panel item icon, it paints itself that fancy gray. How can I get that effect?°dONLNd◊4@** ___°dONLNd€LXÖ*DTo get the fancy System 7 icon dimming to work in your program, use °dONLNdLÖX⁄(t£the icon drawing°dONLNd0XdB(Ä6    routines °dONLNd9XBd⁄)*NPlotIconID or PlotCIconHandle with an IconTransformType of ttSelected. Both of°dONLNdàdpp(å6these routines and °dONLNdõdpp⁄)XKtheir tranform types are used by the Control Panel and are described in the°dONLNdÁp|C(ò6:Macintosh Technical Note “Drawing Icons the System 7 Way.”°dONLNd"àîR* If you want °dONLNd.àRî⁄):Othe same effect under System 6, you’ll have to emulate the dimming of the icons°dONLNd~î†ì(º6Pvia QuickDraw, by installing a color search proc to dim the RGB values that the °dONLNdŒîì†⁄(º±icon uses.  On°dONLNd›†¨6(»68page 146 of Inside Mac volume V is a description of how °dONLNd†6¨⁄(»T!to define and install your custom°dONLNd7¨∏R(‘6 search proc.
  6759. °dONLNdD–fl∞*'8QuickDraw out of memory if debugger invoked by “Jackson”
  6760. °dONLNd}flÎ>* Written:°dONLNdÜfldÎà)L3/11/92°dONLNdéΘ](6Last reviewed:°dONLNdùÎd˜Ç)L4/7/92°dONLNd§®(+6I am getting a strange bug in °dONLNd¬®⁄)ê:which the Macintosh debugger is being invoked by an A-trap°dONLNd˝](76Dmarked “Jackson” when I call SetCCursor in certain situations and a °dONLNd    A]⁄(7{second monitor is hooked°dONLNd    Z'ú(C6Sup. The cursor structure being passed appears to be valid. I’ve also been crashing °dONLNd    ≠ú'⁄(C∫ unexpectedly°dONLNd    ∫'3Y(O6Cin this same spot for the past few weeks. I assume Jackson is some °dONLNd    ˝'Y3⁄(Owkind of error assertion that°dONLNd
  6761. 3?2([68was left in System 7’s Color QuickDraw code. What gives?°dONLNd
  6762. S?K** ___°dONLNd
  6763. WWcx*Jackson was a code °dONLNd
  6764. jWxc⁄)`Iname for 32-Bit QuickDraw. The trap you refer to is in fact never called;°dONLNd
  6765. ¥coù(ã6Sit’s not supposed to be encountered by you ever. The trap is reserved for Apple to °dONLNd cùo⁄(ãª
  6766. use in future°dONLNd o{ı(ó6,versions of Color QuickDraw. If you examine °dONLNd Aoı{⁄)›.the code directly preceding the _Debugger, you°dONLNd p{áè(£6will notice that it is doing,
  6767. Courier
  6768.     °dONLNd çìûö*        MOVEQ      #$19,D0°dONLNd ®ù®§*
  6769.         JSR        ([$1524]) ◊4◊˘
  6770. *(14)
  6771.  of 29(ÏîColor QuickDraw Q&Asˇ4◊#ˇ ˇˇˇˇ#◊ 
  6772. IR,Times
  6773. .+Z-Developer Support Center(-Ê October 1992 /X/
  6774. °dONLNd)<5Ø(QZwhich for you and me is,
  6775. Courier
  6776.     °dONLNdA<Lw*?         MoveQ #25,D0                ; say that memory is full…°dONLNdXK<VT*
  6777. 8        _SysError                    ; and call syserror
  6778. °dONLNdëa<m *the line following would be...
  6779.     °dONLNd∞y<ÑÆ*J        _Debugger ; Hey! sysError came back! Better drop into the debugger
  6780. °dONLNd˚è<õÊ*%What’s all this tell you? You have a °dONLNd èÊõ˛)™;debugger installed that is rts’ing from the SysError vector°dONLNd\õ<ß$(√Z-(you aren’t supposed to return from SysError °dONLNdâõ$߲)Ë)normally), or you have installed your own°dONLNd≥ß<≥ï(œZGSysError vector which is rts’ing. At any rate, if you examine the code °dONLNd˙ßï≥˛(œ≥directly following the°dONLNd≥<ø⁄(€Z debugger statement and see what °dONLNd1≥⁄ø˛)û:it does, you might imagine the source code looks something°dONLNdlø<Àd(ÁZ
  6781. like this:
  6782.     °dONLNdw◊<‚ê*DMemFull       MoveQ #25,D0              ; say that memory is full...°dONLNdº·<Ïc*
  6783. ;              _SysError                 ; and call syserror°dONLNd¯Î<ˆ∏*
  6784. L; If it returns better go into the debugger since its not supposed to return°dONLNdEı<Ü*
  6785. B              _Debugger                 ; Hey! sysError came back!°dONLNdàˇ<
  6786. A*
  6787. ;°dONLNdä    <¥*
  6788. CallNewHand   _NewHandle°dONLNd£<∏*
  6789. L              bne.S  MemFull            ; could not get the memory, just die°dONLNd<(ë*
  6790.               rts
  6791. °dONLNd3<?õ*What’s happening °dONLNd3õ?˛)_Ais that you’re running out of memory somehow (several places call°dONLNdU?<Kı(gZ'MemFull, not just the above place), so °dONLNd|?ıK˛)π5you’d need to use a stack crawl to figure out how you°dONLNd≤K<Wç(sZEgot there. But, the bottom line, QuickDraw has run out of memory and °dONLNd˜KçW˛(s´cannot continue; it tried°dONLNdW<c4(Z5to put up a system error dialog to tell the user and °dONLNdFW4c˛)¯'for some reason the machine did not get°dONLNdnc<o»(ãZPrestarted and the SysError vector returned. You are now in your debugger, since °dONLNdæc»o˛(ãÊ    QuickDraw°dONLNd»o<{X(óZ=put up the system error dialog because it could not continue.
  6792. °dONLNdì<¢¿*'6ditherCopy not supported on LaserWriter or ImageWriter
  6793. °dONLNd=¢<Æb* Written:°dONLNdF¢àƨ)L5/31/91°dONLNdNÆ<∫Å(÷ZLast reviewed:°dONLNd]Æà∫¨)L11/6/91°dONLNdeΔ<“…(ÓZOditherCopy is not supported on LaserWriters or ImageWriters. On a LaserWriter, °dONLNd¥Δ…“˛(ÓÁ
  6794. ditherCopy°dONLNdø“<fi*(˙Z1gets misinterpreted and inverts the image. On an °dONLNd“*fi˛)Ó*ImageWriter it’s treated as a srcCopy. The°dONLNdfi<ÍÁ(ZTImageWriter driver doesn’t support color grafPorts, which is the only way to do the °dONLNdofiÁͲ(pixel°dONLNduÍ<ˆà(ZEimage required for ditherCopy. Use srcCopy instead for both printers.
  6795. °dONLNdª<Á*';Macintosh Color QuickDraw CalcCMask and SeedCFill clarified
  6796. °dONLNd˜<)b* Written:°dONLNdà)¶)L1/1/90°dONLNd)<5Å(QZLast reviewed:°dONLNd)à5≤)L11/21/90°dONLNdA<MÆ(iZHI’m having trouble using CalcCMask and SeedCFill. What am I doing wrong?°dONLNdhM<YN* ___°dONLNdle<q,*-There is some confusion regarding the use of °dONLNdôe,q˛)&the Macintosh Color QuickDraw routines°dONLNd¿q<}0(ôZ0CalcCMask and SeedCFill, which are analogous to °dONLNdq0}˛)Ù(the older CalcMask and SeedFill. Much of°dONLNd    }<âL(•Z8the confusion was caused by early documentation errors. °dONLNd    Q}Lâ˛(•j$Be sure you have the release version°dONLNd    vâ<ïÃ(±ZTof Volume 5 of Inside Macintosh and version 2.0 or later of the MPW interface files.°dONLNd    À°<≠ı*'The correct interface for CalcCMask is: ◊X◊
  6797. *#Color QuickDraw Q&As(Ï˙15)
  6798.  of 29ˇ∞◊#ˇ ˇˇˇˇ#◊ 
  6799. IR,Times
  6800. .+6-Macintosh Technical Notes /4/˘,
  6801. Courier
  6802.     °dONLNd)4˘*#-PROCEDURE CalcCMask(srcBits, dstBits: BitMap;°dONLNd.3>Ω*
  6803. !          srcRect, dstRect: Rect;°dONLNdP=H∏*
  6804.            seedRGB:     RGBColor;°dONLNdqGR∏*
  6805.            matchProc:    ProcPtr;°dONLNdíQ\Ω*
  6806. !          matchData:    LongInt);
  6807. °dONLNd¥gs…*'The correct interface for SeedCFill is:
  6808.     °dONLNd‹ä˘*-PROCEDURE SeedCFill(srcBits, dstBits: BitMap;°dONLNd
  6809. âîΩ*
  6810. !          srcRect, dstRect: Rect;°dONLNd,ìû¬*
  6811. "          seedH, seedV:   INTEGER;°dONLNdOù®§*
  6812.           matchProc:    Ptr;°dONLNdlß≤Ω*
  6813. !          matchData:    LongInt);
  6814. °dONLNdéΩ…]*BEach routine calculates a one-bit deep BitMap representing either °dONLNd–Ω]…⁄(Â{the mask or the fill area°dONLNdÍ…’À(Ò6$depending upon the routine. In both °dONLNd…À’⁄)≥4cases, the source BitMap may be either a BitMap or a°dONLNdC’·∞(˝6Vpixmap, but the destination must be a BitMap, because it must have a depth of one-bit.°dONLNdöÌ˘Å*It is difficult to pass a °dONLNd¥ÌÅ˘⁄)iEpixmap for the source parameter because of Pascal’s type checking. To°dONLNd˙˘(!67get around this difficulty, you can declare a new type:
  6815.     °dONLNd2ö*     BitMapPtr  =  ^BitMap
  6816. °dONLNdM'3„*,then use it to coerce the pixmap as follows:
  6817.     °dONLNdz?JÔ*+     SeedCFill(BitMapPtr(@myPixMap)^, ...);
  6818. °dONLNd¶Ua¯*-If you have a PixMapHandle, do the following:
  6819.     °dONLNd‘mx
  6820. *1     SeedCFill(BitMapPtr(myPixMapHandle^)^, ...);
  6821. °dONLNdÉè∑*SIf you are using a GrafPort (or a window), you can pass myWindow^.portBits and not °dONLNdYÉ∑è⁄(´’have to°dONLNdaèõ)(∑67worry about whether the port uses a BitMap or a PixMap.°dONLNdôß≥*8Most of the other parameters are explained in detail in °dONLNd—ß≥⁄)ˇ&Inside Macintosh. To use the matchProc°dONLNd¯≥øW(€6@and the matchData parameters, though, you need more information.°dONLNd9À◊l*IAs stated in Inside Macintosh, the matchProc parameter is a pointer to a °dONLNdÇÀl◊⁄(Ûäroutine that you would°dONLNdô◊„≤(ˇ6Ylike to use as a custom SearchProc. To better understand how this is used, it is helpful °dONLNdÚ◊≤„⁄(ˇ–to know°dONLNd˙„ÔÙ( 6*how SeedCFill and CalcCMask actually work.°dONLNd%˚r*Both routines start °dONLNd9˚r⁄)ZIby creating a temporary BitMap which, by definition, is one bit deep. The°dONLNdÉW(/6Asource PixMap (or BitMap) is then copied to the temporary BitMap °dONLNdƒW⁄(/uusing CopyBits. This copy°dONLNdfi˝(;6/causes the image to be converted to a depth of °dONLNd
  6822. ˝⁄)Â*one-bit. Now with a normal black-and-white°dONLNd8+Ã(G6\image, the standard CalcMask or SeedFill routine is used to generate the destination BitMap.°dONLNdï7C—*\Most of the real work is done in the original call to CopyBits, which maps the PixMap image °dONLNdÒ7—C⁄(_Ôto°dONLNdÙCOÍ(k6)a monochrome BitMap equivalent. For each °dONLNdCÍO⁄)“0color in the source PixMap, CopyBits will map it°dONLNdNO[Õ(w6'to either black or white. Which colors °dONLNduOÕ[⁄)µ5map to black and which ones to white is determined by°dONLNd´[gc(É6the SearchProc.°dONLNdªs*2SeedCFill installs a default SearchProc that maps °dONLNdÌs⁄)Í/all colors to black except for the color of the°dONLNd    ãπ(ß6\pixel at (seedH,seedV). SeedFill then calculates as usual the fill mask for the white bits . ◊4◊˘
  6823. *E16)
  6824.  of 29(ÏîColor QuickDraw Q&AsˇΔ◊#ˇ ˇˇˇˇ#◊ 
  6825. IR,Times
  6826. .+Z-Developer Support Center(-Ê October 1992 /X/
  6827. °dONLNd<)(EZ*The default SearchProc for CalcCMask maps °dONLNd*)˛)ÿ2all colors to white except the color passed in the°dONLNd])<5Ω(QZJseedRGB parameter. The seedRGB parameter, then, would be the color of the °dONLNdß)Ω5˛(Q€
  6828. item that you°dONLNdµ5<Aì(]Zwanted to “lasso.”°dONLNd»M<Y“*UBut suppose you want to fill over all colors that were shades of green, not just the °dONLNdM“Y˛(u
  6829. particular°dONLNd(Y<eq(ÅZ@shade of green at (seedH,seedV). Or maybe you want to fill over °dONLNdhYqe˛(Åè all colors that are lighter than°dONLNdâe<q˘(çZ%50% brightness. Or maybe you want to °dONLNdÆe˘q˛)Ω3use dark colors as edge colors for CalcCMask. To do°dONLNd‚q<}Ò(ôZZsuch things, you need to pass a pointer to your own SearchProc in the matchProc parameter.°dONLNd=â<ïu*ABecause your matchProc is just a custom search procedure for the °dONLNd~âuï˛(±ìColor Manager, it should be°dONLNdöï<°ı(ΩZ!declared as one, but Volumes I-V °dONLNdªïı°˛)π0of Inside Macintosh have documented this routine°dONLNdϰ<≠ô(…ZKincorrectly. The correct declaration for a custom SearchProc is as follows:,
  6830. Courier
  6831.     °dONLNd8π<ƒ˙*&FUNCTION SearchProc(VAR RGB: RGBColor;°dONLNd_√<Œ    *
  6832. )          VAR result: LongInt) : Boolean;
  6833. °dONLNdâŸ<ÂŒ*Normally, as each SearchProc °dONLNd¶ŸŒÂ˛)íAis installed, it is added to the head of the SearchProc chain, so°dONLNdËÂ<Ò#(
  6834. Z5that it is called before all of the other ones which °dONLNdÂ#Ò˛)Á,were already installed. When a SearchProc is°dONLNdJÒ<˝(Z)installed, it can do one of three things:°dONLNdt    <Z*51. Completely ignore the call by returning FALSE and °dONLNd©    Z˛(1xnot modifying any of the input°dONLNd»<!r(=Z parameters;°dONLNd‘!<-X* >2. Completely handle the call by setting the result parameter °dONLNd!X-˛(Iv$to be the index into the color table°dONLNd7-<9`(UZ=that matches (according to your rules) the RGB parameter. In °dONLNdt-`9˛(U~!that case, the SearchProc returns°dONLNdñ9<E^(aZTRUE;°dONLNdúE<QÀ* R3. Partially handle the call by modifying the RGB parameter, then returning FALSE.°dONLNdÔ]<i´*HIn cases 1 and 3, the Color Manager continues down the SearchProc chain °dONLNd7]´i˛(Ö…until it finds one°dONLNdJi<uv(ëZ
  6835. that returns °dONLNdWivu˛):OTRUE. If none of the custom routines handle the call, then the built-in default°dONLNdßu<Å(ùZ+routine is used. In case 3, you can change °dONLNd“uŞ)…1the RGB color that is being matched. For example,°dONLNdÅ<ç‚(©ZQif you want all shades of green to map to pure green, modify the RGB color, then °dONLNdUÅ‚ç˛(©return°dONLNd\ç<ô∂(µZQFALSE, letting the Color Manager find the index of that green in the color table.°dONLNdÆ•<±o*BIn case 2, you return TRUE to indicate that you handled the call, °dONLNd•o±˛(Õçand you return the color table°dONLNd±<ΩG(ŸZ6index in the result parameter. The Color Manager then °dONLNdE±GΩ˛(Ÿe$uses that index. For example, if you°dONLNdjΩ<…x(ÂZFwant to substitute white for all colors that can’t be matched exactly °dONLNd∞Ωx…˛(Âñin the color table, then each°dONLNdŒ…<’T(ÒZtime °dONLNd”…T’˛)Xyou get called you either return the index into the color table of the exact color, or 0°dONLNd    ,’<·&(˝Z4(which is the index for white) for all other colors.°dONLNd    aÌ<˘l*    A custom °dONLNd    jÌl˘˛)0LSearchProc for SeedCFill and CalcCMask should always return TRUE because the°dONLNd    ∑˘<b(!Zdefault °dONLNd    ø˘b˛)&JColor Manager SearchProc usually doesn’t make sense. Because SeedCFill and°dONLNd
  6836.  
  6837. <’(-ZVCalcCMask are using CopyBits to copy to a 1-bit BitMap, you need to set the result to °dONLNd
  6838. `’˛(-Û    be either°dONLNd
  6839. j<”(9Z!0 or 1 (the only possible values °dONLNd
  6840. ã”˛)ó@in a 1-bit BitMap). A result of 0 is white, and a result of 1 is°dONLNd
  6841. Ã<)Y(EZblack.°dONLNd
  6842. ”5<A∞*All colors for SeedCFill °dONLNd
  6843. Ï5∞A˛)tFthat should be “filled over” would generate a result of 0 (white), and°dONLNd 3A<M(iZ4all colors that stop the fill generate a 1 (black). °dONLNd gAM˛)›3SeedFill is then called to fill the white area. All°dONLNd õM<YÒ(uZ[colors for CalcCMask that you want to form boundaries should generate results of 1 (black).°dONLNd ˜e<q[*/When your SearchProc gets called, the gdRefCon °dONLNd &e[q˛(çyfield of the current GDevice°dONLNd Cq<}Ñ(ôZC(theGDevice^^.gdRefCon) contains a pointer to the following record:
  6844.     °dONLNd áâ<îØ*    matchRec  =  RECORD°dONLNd üì<ûπ*
  6845.       red:       Integer;°dONLNd πù<®π*
  6846.       green:     Integer; ◊X◊
  6847. *(Color QuickDraw Q&As(Ï˙17)
  6848.  of 29ˇv◊#ˇ ˇˇˇˇ#◊ 
  6849. IR,Times
  6850. .+6-Macintosh Technical Notes /4/˘,
  6851. Courier
  6852.     °dONLNd(ï*      blue:      Integer;°dONLNd'2ï*
  6853.       matchData: LongInt;°dONLNd41<@*
  6854.     END;
  6855. °dONLNd=GSd*DThe red, green, and blue parameters for SeedCFill are the values of °dONLNdÅGdS⁄(oÇthe color of the pixel at°dONLNdõS_T({6;(seedH,seedV). For CalcCMask, they are the fields from the °dONLNd÷ST_⁄({rseedRGB parameter. Your°dONLNdÓ_k˘(á6.SearchProc can use this information to decide °dONLNd_˘k⁄)·-which colors are “fill-over” colors and which°dONLNdJkwß(ì6colors are “boundary” colors. °dONLNdhkßw⁄)è<For example, if you always set (seedH,seedV) to be the mouse°dONLNd•wÉ7(ü6point, °dONLNd¨w7É⁄)Wyour SearchProc then bases its decisions using the color of the pixel under the cursor.°dONLNdÉè±(´6YFor example, the user clicks on a shade of green, so all shades of green get filled over.°dONLNd^õßæ*!The matchData field contains the °dONLNdõæß⁄)¶5value that you passed into the SeedCFill or CalcCMask°dONLNdµß≥"(œ65routines in the matchData parameter. The use of this °dONLNdÍß"≥⁄(œ@%field is completely user-defined. For°dONLNd≥ø-(€69example, since your SearchProc routine may be a separate °dONLNdI≥-ø⁄(€K"module, you might want to use this°dONLNdløÀ∫(Á6Vfield to pass a handle to your variables. This field can contain a handle, a pointer, °dONLNd¬ø∫À⁄(Áÿa long°dONLNd…À◊E(Û6Cinteger, or whatever; or you can just ignore this field altogether.°dONLNd
  6856. „Ôô*JWarning: There are some features of CalcCMask and SeedCFill you should be °dONLNdW„ôÔ⁄( ∑ aware of. To°dONLNddÔ˚˘(6-understand them, you should be familiar with °dONLNdëÔ˘˚⁄)·+the use of CalcMask and SeedFill, which are°dONLNdΩ˚Ò(#6,described in the QuickDraw chapter of IM IV.°dONLNdÍh*CalcCMask and °dONLNd¯h⁄)PJSeedCFill both use a parameter set that is very similar to the one used by°dONLNdC+í(G6CopyBits. CalcMask and °dONLNdZí+⁄)zDSeedFill, however, are a different story. Instead of passing bitmaps°dONLNdü+7j(S6and rectangles to °dONLNd±+j7⁄)RKSeedFill and CalcMask, these routines use an unusual set of parameters that°dONLNd˝7CÜ(_6Mdescribe the memory to be operated upon in terms of pointers, height, width, °dONLNdJ7ÜC⁄(_§and offsets to the°dONLNd]CO(k6/next row (rowBytes). Although these parameters °dONLNdåCO⁄),are fairly easy to calculate, there are some°dONLNdπO[M(w6 limitations.°dONLNdΔgsß* The most restrictive limitation °dONLNdÊgßs⁄)è@is that the width of the rectangle used must be an even multiple°dONLNd'sè(õ6Pof 16 bits. This limitation exists because the width of the rectangle is passed °dONLNdwsè⁄(õ≠to SeedFill and°dONLNdáãò(ß6CalcMask as a number of °dONLNdüòã⁄)Ä?words (2 bytes). When calculating this parameter, SeedCFill and°dONLNdflãó´(≥6LCalcCMask round down to an even word boundary. This rounding means that the °dONLNd+ã´ó⁄(≥…
  6857. rectangles°dONLNd6ó£Δ(ø6Yyou pass to CalcCMask and SeedCFill should be an even multiple of 16 pixels in width. If °dONLNdèóΔ£⁄(ø‰they°dONLNdî£ØB(À6@are not, then the rightmost portion of the mask will be garbage.°dONLNd’ª«—*(To figure out the color of the pixel at °dONLNd˝ª—«⁄)π3(seedH,seedV), SeedCFill calls GetCPixel. GetCPixel°dONLNd    1«”…(Ô6)finds the color of the pixel at (h,v) in °dONLNd    Z«…”⁄)±7the current port. Therefore, if you pass a PixMap which°dONLNd    í”fl…(˚6Zis not the PixMap of the current port you will get bizarre results. In other words, seedH °dONLNd    Ï”…fl⁄(˚Áand°dONLNd    flΪ(6\seedV are expressed in the local coordinates of the current port, not the coordinate of the °dONLNd
  6858. LflªÎ⁄(Ÿsource°dONLNd
  6859. SΘA(6PixMap.°dONLNd
  6860. [à*You have two methods °dONLNd
  6861. pà⁄)pEto make it work. First, always pass the PixMap of the current port as°dONLNd
  6862. ∂œ(76Wthe source parameter. If you are using an off-screen PixMap, it is a good idea to have °dONLNd
  6863. œ⁄(7Ìan°dONLNd '*(C6<associated port for it, and then call SetPort, passing it a °dONLNd L*'⁄(CH$pointer your off-screen port, before°dONLNd q'3s(O6you call SeedCFill.°dONLNd Ö?Kú*FThe second method involves letting SeedCFill get some wrong value for °dONLNd À?úK⁄(g∫ the color at°dONLNd ÿKW3(s64(seedH,seedV) then using your own custom SearchProc °dONLNd K3W⁄(sQ to do the real work. The default°dONLNd -Wc(67SearchProc for SeedCFill relies on getting the correct °dONLNd dWc⁄)˛'color, but your SearchProc doesn’t have°dONLNd åco%(ã6to.°dONLNd ê{áK*
  6864. SeedCFill °dONLNd ö{Ká⁄)3Nalso makes the assumption that the seedH and seedV parameters are in the local°dONLNd Èáìu(Ø6Hcoordinate system of the destination BitMap. This assumption comes into °dONLNd
  6865. 1áuì⁄(Øìplay when SeedCFill°dONLNd
  6866. Eìü (ª67calculates the seedH and seedV parameters for SeedFill. ◊4◊˘
  6867. *118)
  6868.  of 29(ÏîColor QuickDraw Q&Asˇ`◊#ˇ ˇˇˇˇ#◊ 
  6869. IR,Times
  6870. .+Z-Developer Support Center(-Ê October 1992 /X/
  6871. °dONLNd<)ñ(EZAll this means that °dONLNdñ)˛)ZHSeedCFill only works correctly if the source PixMap, destination PixMap,°dONLNd])<5ú(QZand current port all °dONLNdr)ú5˛)`Euse the same coordinate system. Because of the above problem, this is°dONLNd∏5<A€(]ZWalmost automatic since the current port’s portRect and the bounds of the source PixMap °dONLNd5€A˛(]˘have to°dONLNdA<Mü(iZbe the same anyway.°dONLNd+Y<e¯*&The easiest way to make all this work °dONLNdQY¯e˛)º3is to have your main port be an even multiple of 16°dONLNdÖe<q¥(çZpixels wide. Then, make °dONLNdùe¥q˛)xCsure that your source and destination structures (PixMap or BitMap)°dONLNd·q<}$(ôZ4are all the same size and all have origins of (0,0).
  6872. °dONLNdï<§;*'#System 7.0ß1 BitMapToRgn limitation
  6873. °dONLNd:§<∞b* Written:°dONLNdC§à∞¶)L1/1/90°dONLNdJ∞<ºÅ(ÿZLast reviewed:°dONLNdY∞ຨ)L12/7/90°dONLNda»<‘!(Z-BitMapToRegion does not work as described in °dONLNdé»!‘˛)Â*the Macintosh Tech Note “32-Bit QuickDraw:°dONLNdπ‘<‡¿(¸ZJVersion 1.2 Features” for a PixMap with baseAddr = (NuBus address). Which °dONLNd‘¿‡˛(¸fi
  6874. calls support°dONLNd‡<Ï5(Z1PixMap 32-bit base addressing with pmVersion = 4?°dONLNdC¯<N*___°dONLNdG<é*=As of System 7.0ß1, BitMapToRgn cannot handle a bitmap whose °dONLNdÑé˛(8¨base address is in the°dONLNdõ<(E(DZ7NuBus address space or any bitmap that requires 32-bit °dONLNd“E(˛(Dc%addressing. The problem will be fixed°dONLNd¯(<4M(PZfor °dONLNd¸(M4˛)XSystem 7’s final release. BitMapToRgn seems to be the only call that doesn’t yet support°dONLNdU4<@∂(\Z32-bit addressed bitmaps.°dONLNdoL<X]*X-Ref:°dONLNdvX<dù* EDTS Macintosh Technical Note “32-Bit QuickDraw: Version 1.2 Features”
  6875. °dONLNdº|<ãv*'*Macintosh Color QuickDraw and packed PICTs
  6876. °dONLNdÁã<ób* Written:°dONLNdãàó¶)L1/1/90°dONLNd˜ó<£Å(øZLast reviewed:°dONLNdóࣨ)L12/7/90°dONLNdØ<ª(◊Z(Does Macintosh 32-Bit QuickDraw support °dONLNd6ت˛)’-packed PICTs? What’s the technique for saving°dONLNddª<«t(„Z<packed PICT formats? What compression schemes are supported?°dONLNd°«<”N* ___°dONLNd•fl<θ*%Color QuickDraw has always supported °dONLNd fl¸Î˛)¿1packed PICTs. See Inside Macintosh, Volume V, for°dONLNd¸Î<˜n(Z details on °dONLNdÎn˜˛)2Ghow CLUT PixMaps are packed. Under 32-Bit QuickDraw, to pack direct RGB°dONLNdO˜<õ(ZPixMaps in PICTs, °dONLNda˜õ˛)_Hcall CopyBits with the packType field in the source PixMap set to one of°dONLNd™<P(+Z9the following constants that apply to direct RGB PixMaps:°dONLNd‰<'F*90 - default packing (pixelSize 16 defaults to packType 3 °dONLNdF'˛(Cd%and pixelSize 32 defaults to packType°dONLNdC'<3F(OZ4)°dONLNdF3<?Ä* 1 - no packing°dONLNdU?<K¯* (2 - remove pad byte (32-bit pixels only)°dONLNd~K<Wl* A3 - run-length encoding by pixel size chunks (16-bit pixels only)°dONLNd¿W<cc* ?4 - run-length encoding, all of one component at the time, one °dONLNdˇWcc˛(Å"scan line at a time (24-bit pixels°dONLNd"c<oU(ãZonly)°dONLNd({<á*&Scheme 4 will store the alpha channel °dONLNdN{á˛)¥8also if cmpCount is set to to four. PackSize is not used°dONLNdáá<ìO(ØZ;and should be set to zero for compatibility reasons. These °dONLNd¬áOì˛(Øm#are the only compression techniques°dONLNdÊì<ü•(ªZsupported at this time. ◊X◊
  6877. *1Color QuickDraw Q&As(Ï˙19)
  6878.  of 29ˇfi◊#ˇ ˇˇˇˇ#◊ 
  6879. IR,Times
  6880. .+6-Macintosh Technical Notes /4/˘
  6881. °dONLNd)8-*'(Macintosh PICT color picture file format
  6882. °dONLNd)8D>* Written:°dONLNd28dDÇ)L1/1/90°dONLNd9DP](l6Last reviewed:°dONLNdHDdPé)L11/21/90°dONLNdQ\h&(Ñ6Is °dONLNdT\&h⁄)Wthere a general file format for color pictures that is common to all of the color paint°dONLNd¨ht‹(ê6(programs? If so, where is it documented?°dONLNd’tÄ** ___°dONLNdŸåò]*DApple supports (and encourages developers to support) one file type °dONLNdå]ò⁄(¥{for pictures: the PICT file°dONLNd9ò§(¿61type. Most paint-type programs handle PICT files.°dONLNdk∞º4*;A PICT file is composed of two parts in its data fork; the °dONLNd¶∞4º⁄(ÿR#first 512 bytes for the file header°dONLNd º»v(‰6Iwhich contain application-dependent information. You have to contact the °dONLNdºv»⁄(‰îindividual publishers°dONLNd)»‘ù(6to find out their particular °dONLNdF»ù‘⁄)Ö>data structures. For example, you can contact Claris Technical°dONLNdÖ‘‡L(¸6 Support at °dONLNdê‘L‡⁄)4JAppleLink CLARIS.TECH or (415) 962-0371 for the file header MacDraw writes°dONLNd€‡ÏJ(6
  6883. to its files.°dONLNdȯ≈*SThe rest of the data in the file is picture data as created by Macintosh QuickDraw °dONLNd<¯≈⁄( „with°dONLNdAA(,6=OpenPicture. You can find the information about this data in °dONLNd~A⁄(,_Volume V of Inside Macintosh°dONLNdõa(86E(pages 84-105); this section also shows how to read/write PICT files.°dONLNd·(4B*You can °dONLNdÈ(B4⁄)*Qalso check the Macintosh Tech Note “Displaying Large PICT Files” for more details°dONLNd;4@](\6on the subject.°dONLNdKLX>*X-Refs:°dONLNdSXdu* FDTS Macintosh Technical Note “QuickDraw’s Internal Picture Definition”°dONLNdödpA* :DTS Macintosh Technical Note “Displaying Large PICT Files”
  6884. °dONLNd’àó∫*'<Mac PixMap is clipped to visRgn defined by screenBits.bounds
  6885. °dONLNdó£>* Written:°dONLNdód£Ç)L1/1/90°dONLNd"£Ø](À6Last reviewed:°dONLNd1£dØé)L11/21/90°dONLNd:ª«}(„6GI’m drawing into a large offscreen bitmap (PixMap), but anything drawn °dONLNdŪ}«⁄(„õoutside the 640 by°dONLNdî«”Ñ(Ô6K480 pixel Macintosh screen area doesn’t get written to the PixMap. Why not?°dONLNd‡”fl** ___°dONLNd‰Î˜@*6When you create a new port with OpenPort or OpenCPort °dONLNdÎ@˜⁄(^ the visRgn is initialized to the°dONLNd;˜9(6<rectangular region defined by screenBits.bounds (IM I:163). °dONLNdw˜9⁄(W"If your port has a large portRect,°dONLNdö(+6*any drawing will be clipped to the visRgn °dONLNdƒ⁄)ÿ,and you will lose any drawing outside of the°dONLNdÒ°(76screenBits.bounds rectangle.°dONLNd'3ä*QTo correct this set the visRgn of the port to coincide with your port’s portRect °dONLNd_'ä3⁄(O®after creating the°dONLNdr3?/([6port.°dONLNdxKW*5Also note that OpenPort initializes the clipRgn to a °dONLNd≠KW⁄(s8%wide-open rectangular region (-32768,°dONLNd”Wcˇ(6--32768, 32767, 32767). Some operations, like °dONLNdWˇc⁄)Á-OpenPicture, can fail with this setup, so try°dONLNd.co…(ã6'setting clipRgn to a smaller rectangle.°dONLNdV{á>*X-Refs:°dONLNd^áì4* 8DTS Macintosh Technical Note “Pictures and Clip Regions”°dONLNdóìüo* CDTS Macintosh Technical Note “Drawing into an Off-Screen Pixel Map” ◊4◊˘
  6886. *120)
  6887.  of 29(ÏîColor QuickDraw Q&Asˇ\◊#ˇ ˇˇˇˇ#◊ 
  6888. IR,Times
  6889. .+Z-Developer Support Center(-Ê October 1992 /X/
  6890. °dONLNd)<8µ(TZ5Using Mac System 7 OpenCPicture for higher resolution
  6891. °dONLNd68<Db* Written:°dONLNd?8àD¶)L1/1/90°dONLNdFD<PÅ(lZLast reviewed:°dONLNdUDàP¨)L12/7/90°dONLNd]\<hs(ÑZAWe want to use OpenCPicture for higher resolution, not for color °dONLNdû\sh˛(Ñëper se. Can OpenCPicture in°dONLNd∫h<t–(êZOSystem 7 be used with non-Color as well as Color QuickDraw Macintosh computers?°dONLNd
  6892. t<ÄN* ___°dONLNdå<òW*Yes, °dONLNdåWò˛)Owith System 7, OpenCPicture can be used to create extended PICT2 files from all°dONLNdcò<§˜(¿Z"Macintosh computers. Under System °dONLNdÖò˜§˛)ª26.0.7 or later, you must test for 32-Bit QuickDraw
  6893. °dONLNd∏§<∞8(ÃZ&before using OpenCPicture. You can do  °dONLNdfi§8∞˛)¸ this by calling Gestalt with the°dONLNdˇ∞<ºñ(ÿZBgestaltQuickDrawVersion selector. If it returns gestalt32BitQD or °dONLNdA∞ñº˛(ÿ¥greater, then 32-Bit°dONLNdVº<»´(‰ZQuickDraw is installed.
  6894. °dONLNdn‡<ÔY*'(How to identify 32-Bit QuickDraw version
  6895. °dONLNdóÔ<˚b* Written:°dONLNd†Ôà˚¶)L1/1/90°dONLNdß˚<Å(#ZLast reviewed:°dONLNd∂˚à≤)L11/21/90°dONLNdø<Â(;ZSHow can my program find out which version of Macintosh 32-Bit QuickDraw is running?°dONLNd<+N* ___°dONLNd7<CÇ*The following °dONLNd%7ÇC˛)FKcode snippet demonstrates how to use the Gestalt Manager to determine which°dONLNdqC<Ob(kZversion °dONLNdyCbO˛)&Tof 32-Bit QuickDraw is installed. There is no way to determine the version of 32-Bit°dONLNdŒO<[fi(wZQQuickDraw before Gestalt. For 32-Bit QuickDraw version 1.2, Gestalt returns 2.2. °dONLNdOfi[˛(w¸IM VI°dONLNd%[<gı(ÉZ(describes the Gestalt Manager in detail.,
  6896. Courier
  6897.     °dONLNdNs<~á*#defineTRUE0xFF°dONLNd^}<à}*
  6898.  
  6899. #defineFALSE0°dONLNdlá<íπ*
  6900. #define Gestalttest0xA1AD°dONLNdÜë<ú†*
  6901. #define NoTrap0xA89F°dONLNdõ•<∞Z*main()°dONLNd¢Ø<∫A*
  6902. {°dONLNd§π<ƒi*
  6903.     OSErrerr;°dONLNdÆ√<Œx*
  6904. longfeature;°dONLNdª◊<‚r*>if ((GetTrapAddress(Gestalttest) != GetTrapAddress(NoTrap))) {°dONLNd˙·<Ï1*
  6905. 1err = Gestalt(gestaltQuickdrawVersion, &feature);°dONLNd,Î<ˆs*
  6906. if (!err) {°dONLNd8ı<·*
  6907. !if ((feature & 0x0f00) == 0x0000)°dONLNdZˇ<
  6908. ©*
  6909. Iprintf ("We have Original QuickDraw version 0.%x\n", (feature & 0x00ff));°dONLNd§    <˙*
  6910. &else if ((feature & 0x0f00) == 0x0100)°dONLNdÀ<ö*
  6911. Fprintf ("We have 8 Bit QuickDraw version 1.%x\n", (feature & 0x00ff));°dONLNd<(˙*
  6912. &else if ((feature & 0x0f00) == 0x0200)°dONLNd9'<2ü*
  6913. Gprintf ("We have 32 Bit QuickDraw version 2.%x\n", (feature & 0x00ff));°dONLNdÅ1<<P*
  6914. else°dONLNdÜ;<F“*
  6915. printf ("We don't have QD\n");°dONLNd•E<PA*
  6916. }°dONLNdßO<ZP*
  6917. else°dONLNd¨Y<dÊ*
  6918. "printf ("Gestalt err = %i\n",err);°dONLNdœc<nA*
  6919. }°dONLNd—m<xP*
  6920. else°dONLNd÷w<Ç¥*
  6921. printf ("No Gestalt\n");°dONLNdÔÅ<åA*
  6922. } ◊X◊
  6923. *DColor QuickDraw Q&As(Ï˙21)
  6924.  of 29ˇ»◊#ˇ ˇˇˇˇ#◊ 
  6925. IR,Times
  6926. .+6-Macintosh Technical Notes /4/˘
  6927. °dONLNd,†*Macintosh QDError function under System 6 and System 7
  6928. °dONLNd7,8>* Written:°dONLNd@,d8Ç)L1/1/90°dONLNdG8D](`6Last reviewed:°dONLNdV8dDà)L12/7/90°dONLNd^P\»(x6Under what System 7 and System °dONLNd}P»\⁄)∞66 conditions is it legal to call the Macintosh QDError°dONLNd¥\hD(Ñ6    function?°dONLNdæht** ___°dONLNd¬Äåfi*&Under System 7, QDError can be called °dONLNdËÄfiå⁄)Δ0from all Macintosh computers. (System 7 supports°dONLNdåò©(¥6CRGBForeColor, RGBBackColor, GetForeColor, and GetBackColor for all °dONLNd\å©ò⁄(¥«    Macintosh°dONLNdfò§M(¿6
  6929. computers °dONLNdpòM§⁄)5Jas well.) On a non-Color QuickDraw Macintosh, QDError always returns a “no°dONLNdª§∞ (Ã6 error.” Under System 6, QDError °dONLNd€§ ∞⁄)≤0cannot be used for non-Color QuickDraw Macintosh°dONLNd ∞ºB(ÿ6systems.
  6930. °dONLNd‘„ò*'6Macintosh CopyBits transfer modes changed for System 7
  6931. °dONLNdL„Ô>* Written:°dONLNdU„dÔÇ)L1/1/90°dONLNd\Ô˚](6Last reviewed:°dONLNdkÔd˚à)L12/7/90°dONLNds
  6932. (/6.Why do some Macintosh CopyBits transfer modes °dONLNd°
  6933. ⁄)Ú+produce different results for System 7 than°dONLNdÕZ(;6
  6934. for System 6?°dONLNd€+** ___°dONLNdfl7Cñ*LUnder System 6, the srcOr, srcXor, srcBic, notSrcCopy, notSrcOr, notSrcXor, °dONLNd+7ñC⁄(_¥
  6935. and notSrcBic°dONLNd9COØ(k6Xtransfer modes do not produce the same effect for a 16- or 32-bit (direct) pixel map as °dONLNdëCØO÷(kÕfor an 8°dONLNdôC÷O⁄)'-°dONLNdöO[Œ(w6Xbit or shallower (indexed) pixel map. With Color QuickDraw these classic transfer modes °dONLNdÚOŒ[⁄(wÏon°dONLNdı[g6(É6direct °dONLNd¸[6g⁄)Rpixel maps aren’t color based; they’re pixel value based. Color QuickDraw performs°dONLNdOgsº(è6Zlogical operations corresponding to the transfer mode on the source and destination pixel °dONLNd©gºs⁄(è⁄values°dONLNd∞s©(õ6!to get the resulting pixel value.°dONLNd“ãóÙ*/For example, say that a multicolored source is °dONLNdãÙó⁄)‹/being copied onto a black and white destination°dONLNd1ó£Ë(ø6,using the srcOr transfer mode, and both the °dONLNd]óË£⁄)–3source and destination are 8 bits per pixel. Except°dONLNdë£ØV(À6Din unusual cases, the pixel value for black on an indexed pixel map °dONLNd’£VØ÷(Àthas all its bits set, so an 8°dONLNdÚ£÷Ø⁄)Ä-°dONLNdÛØª¿(◊6`bit black pixel has a pixel value of $FF. Similarly, the pixel value for white has all its bits °dONLNdSØ¿ª⁄(◊ficlear,°dONLNdZª«’(„6*so an 8-bit white pixel has a pixel value °dONLNdѪ’«⁄)Ω5of $00. CopyBits takes each pixel value of the source°dONLNd∫«”Ø(Ô6and performs a logical OR with °dONLNdŸ«Ø”⁄)ó=the corresponding pixel value of the destination. Using OR to°dONLNd”flX(˚6Dcombine any value with 0 results in the original value, so using OR °dONLNd[”Xfl⁄(˚vto combine any pixel value°dONLNdvflÎ0(6=with the pixel value for white results in the original pixel °dONLNd≥fl0Î⁄(Nvalue.  Using OR to combine any°dONLNd”Θí(6Qvalue with 1 results in 1, so using OR to combine any pixel value with the pixel °dONLNd$Îí˜⁄(∞value for black°dONLNd4˜≤(6Vresults in the pixel value for black. The resulting image shows the original image in °dONLNdä˜≤⁄(–    all areas°dONLNdîp(+6Cwhere the destination image was white and shows black in all areas °dONLNd◊p⁄(+éwhere the destination°dONLNdÌj(76image was black.°dONLNd˛'3~*HTake the same example, but this time make the source and destination 32 °dONLNd    F'~3⁄(Oúbits per pixel. The°dONLNd    Z3?ú([6direct-color pixel value for °dONLNd    w3ú?⁄)Ñ@black is $00000000 and the direct-color pixel value for white is°dONLNd    ∏?K’(g6%$00FFFFFF. CopyBits still performs a °dONLNd    ›?’K⁄)Ω6logical OR on the source and destination pixel values,°dONLNd
  6936. KW(s62but notice what happens in this case. Using OR to °dONLNd
  6937. FKW⁄)˘'combine any source pixel value with the°dONLNd
  6938. nWcñ(6Qpixel value for white results in white, and using OR to combine any source pixel °dONLNd
  6939. øWñc⁄(¥value with the°dONLNd
  6940. ŒcoA(ã6Cpixel value for black results in the original color. The resulting °dONLNd cAo⁄(ã_image shows the original image°dONLNd 0o{%(ó6in °dONLNd 3o%{⁄)
  6941. Vall areas where the destination image was black and shows white in all areas where the°dONLNd ä{á“(£6Ydestination image was white—roughly the opposite of what you see on an indexed pixel map.°dONLNd ‰ìü¡*LThe newer transfer modes addOver, addPin, subOver, subPin, adMax, and adMin °dONLNd 0ì¡ü⁄(ªflwork°dONLNd 5ü´`(«6consistently at °dONLNd Eü`´⁄)HMall pixel depths, and often, though not always, correspond to the theoretical ◊4◊˘
  6942. (Ï622)
  6943.  of 29(ÏîColor QuickDraw Q&AsˇË◊#ˇ ˇˇˇˇ#◊ 
  6944. IR,Times
  6945. .+Z-Developer Support Center(-Ê October 1992 /X/
  6946. °dONLNd<)r(EZ>effect of the old transfer modes. For example, the adMin mode °dONLNd>r)˛(Eêworks similarly to the srcOr°dONLNd[)<5≈(QZJmode on both direct and indexed pixel maps. Also, 1-bit deep source pixel °dONLNd•)≈5˛(Q„    maps work°dONLNdØ5<A‹(]ZXconsistently and predictably regardless of the pixel depth of the destination even with °dONLNd5‹A˛(]˙the old°dONLNdA<MÜ(iZtransfer modes.°dONLNdY<e*>Under System Software 7.0, the old transfer modes now perform °dONLNd]Ye˛(Åùby calculating with colors°dONLNdxe<qâ(çZIrather than pixel values. You’ll find that transfer modes like srcOr and °dONLNd¡eâq˛(çßsrcBic work much more°dONLNd◊q<}Û(ôZ'consistently even on direct pixel maps.
  6947. °dONLNdˇï<§r*'+Which QuickDraw versions support SetEntries
  6948. °dONLNd+§<∞b* Written:°dONLNd4§à∞¶)L3/3/92°dONLNd;∞<ºÅ(ÿZLast reviewed:°dONLNdJ∞ຨ)L6/30/92°dONLNdR»<‘©(ZHI’m calling SetEntries to update the onscreen CLUT. Who implements this °dONLNdö»©‘˛(«call? Does 32-Bit°dONLNd¨‘<‡ñ(¸ZBQuickDraw? In other words, does the 32-Bit QuickDraw INIT need to °dONLNdÓ‘ñ‡˛(¸¥be around for this to°dONLNd‡<Ï(Z%work? What about monochrome machines?°dONLNd+¯<Ä*AI’m creating offscreen buffers by hand instead of using GWorlds. °dONLNdl¯Ä˛( ûIs this the proper way of°dONLNdÜ<ı(,ZZdoing offscreen buffering when we don’t want to require the user to have 32-Bit QuickDraw?°dONLNd·<N* ___°dONLNdÂ(<4j*?SetEntries is part of the Color Manager, which exists with all °dONLNd$(j4˛(PàColor QuickDraw versions. A°dONLNd@4<@{(\ZCgood rule of thumb to follow is that if it is documented in Inside °dONLNdÉ4{@˛(\ôMacintosh Volume V, you°dONLNdõ@<LK(hZ8don’t need 32-Bit QuickDraw to use it. Inside Macintosh °dONLNd”@KL˛(hi!Volume V documents standard Color°dONLNdıL<XX(tZ2QuickDraw. SetEntries does not work on monochrome °dONLNd'LXX˛(tvMacintosh models, including the°dONLNdGX<d€(ÄZClassic II, SE, and PowerBooks.°dONLNdgp<|„*ZOffscreen buffering: You should always use GWorlds if they exist; use Gestalt to test for °dONLNd¡p„|˛(òthem.°dONLNd«|<àƒ(§ZUThis will assure that you can take advantage of the latest speed improvements. It is °dONLNd|ƒà˛(§‚ important to°dONLNd)à<îÛ(∞ZMremember that under system 7 NewGWorld and accompanying calls are present in °dONLNdvàÛî˛(∞all°dONLNdzî<†Ò(ºZTMacintosh computers including b&w systems such as Classic and PowerBook 100 systems.
  6949. °dONLNdœ∏<«*'+Macintosh pixel map maximum rowBytes change
  6950. °dONLNd˚«<”b* Written:°dONLNd«à”¨)L4/22/91°dONLNd ”<flÅ(˚ZLast reviewed:°dONLNd”àfl¨)L6/10/91°dONLNd#Î<˜Ÿ(ZThe Color QuickDraw section of °dONLNdBΟ˜˛)ù=Inside Macintosh Volume VI states that the restriction on the°dONLNdĘ<¯(ZZrowBytes field in a pixMap has been relaxed from $2000 to $4000. When did this happen? Is °dONLNd⁄˜¯˛(it°dONLNd›<ı(+Z\true for all 32-bit QuickDraw versions? This affects our user configuration recommendations.°dONLNd:<N* ___°dONLNd>'<3*(The maximum rowBytes extension to $3FFF °dONLNdf'3˛)ÿ/or less applies only to 32-bit QuickDraw. Using°dONLNdñ3<?L([Z5PixMaps with rowBytes greater than $1FFF when 32-bit °dONLNdÀ3L?˛([j%QuickDraw is not present is likely to°dONLNdÒ?<Kà(gZcause problems °dONLNd    ?àK˛)LHsuch as garbage images or system crashes. Remember that 32-bit QuickDraw°dONLNd    IK<WË(sZ#is always present under System 7.0.
  6951. °dONLNd    mo<~ñ*'3Use assembly to flip a 24-bit off-port color PixMap
  6952. °dONLNd    °~<äb* Written:°dONLNd    ™~àä¶)L5/7/91°dONLNd    ±ä<ñÅ(≤ZLast reviewed:°dONLNd    ¿äàñ¨)L7/25/91 ◊X◊
  6953. (ÏZColor QuickDraw Q&As(Ï˙23)
  6954.  of 29ˇ>◊#ˇ ˇˇˇˇ#◊ 
  6955. IR,Times
  6956. .+6-Macintosh Technical Notes /4/˘
  6957. °dONLNd)Ä*MWhat’s the best approach to horizontally flip a 24-bit off-port color PixMap?°dONLNdN)5** ___°dONLNdRAM^*BUnfortunately, you won’t be able to use CopyBits for this kind of °dONLNdîA^M⁄(i|procedure; you’ll have to°dONLNdÆMY∑(u6write your own routine to move °dONLNdÕM∑Y⁄)ü:each pixel. I’d suggest doing this in assembly language to°dONLNdYe!(Å67squeeze the best possible performance out of your code.
  6958. °dONLNd@}åí*':Construct a 'clut' instead of changing b/w palette entries
  6959. °dONLNd{åò>* Written:°dONLNdÑådòà)L6/10/91°dONLNdåò§](¿6Last reviewed:°dONLNdõòd§Ç)L8/1/91°dONLNd¢∞º°(ÿ6UHow can I change the first and last (white and black) entries in a Macintosh palette?°dONLNd¯º»** ___°dONLNd¸‘‡Δ*YThe answer to your question about changing the black and white entries in a palette is a °dONLNdU‘Δ‡⁄(¸‰little°dONLNd\‡ÏÀ(6Zstrange. You can’t simply change the palette associated with an on-screen window, because °dONLNd∂‡ÀÏ⁄(Ètoo°dONLNd∫ϯŸ(6amany portions of the Toolbox/OS assume that the first entry is white and the last entry is black.°dONLNdz*However, what you °dONLNd.zä)bcan°dONLNd1äƒ)F do is create an off-screen GWorld and construct a 'clut' for it that °dONLNdwƒ⁄(,‚does°dONLNd|0(86=what you want. Creating the 'clut' is fairly straightforward:,
  6960. Courier
  6961.     °dONLNd∫(3˛*./* Making a reversed gray-scale color table */°dONLNdÈ<GÅ*CTabHandle offColors;°dONLNdˇP[l*DoffColors = (CTabHandle) NewHandleClear (sizeof (ColorTable) + 255 *°dONLNdDZe¬*
  6962. "              sizeof (ColorSpec));°dONLNdgdoü*
  6963. (**offColors).ctSize = 255;°dONLNdÉny+*
  6964. 7for (index = 0; index <= (**offColors).ctSize; index++)°dONLNdªxÉ'*
  6965.   {°dONLNdøÇç*
  6966. 0    (**offColors).ctTable [index].value = index;°dONLNdåó]*
  6967. A    (**offColors).ctTable [index].rgb.red = (index << 8) | index;°dONLNd2ñ°g*
  6968. C    (**offColors).ctTable [index].rgb.green = (index << 8) | index;°dONLNdv†´b*
  6969. B    (**offColors).ctTable [index].rgb.blue = (index << 8) | index;°dONLNdπ™µ'*
  6970.   }°dONLNdΩ¥øö*
  6971. (**offColors).ctFlags = 0;°dONLNdÿæ…Ã*
  6972. $(**offColors).ctSeed = GetCTSeed ();
  6973. °dONLNd˝‘‡\*ENote that using this 'clut' with an off-screen GWorld will work fine °dONLNdB‘\‡⁄(¸z_except_ if you attempt to°dONLNd]‡Ïo(6Fdraw text into the GWorld. Apparently drawing text off screen carries °dONLNd£‡oÏ⁄(çthe same assumptions°dONLNd∏ϯÆ(6 that all drawing does on screen.°dONLNdŸœ*XOnce you have done your off-screen drawing with the reversed 'clut' as described above, °dONLNd1œ⁄(,Ìall°dONLNd5 (86Wthat remains is to CopyBits from your off-screen GWorld to your on-screen window. Your °dONLNdå ÷(8Ëon°dONLNdé÷⁄) -°dONLNdè(<(D6>screen window will need the appropriate palette. Fortunately, °dONLNdÕ<(⁄(DZ"constructing that palette from the°dONLNd(4](P6'clut' is trivial:
  6974.     °dONLNd@KÆ*/* Make a palette out of it */°dONLNd"JUè*
  6975. KaPalette = NewPalette (offColors, (**offColors).ctSize + 1, pmTolerant, 0);
  6976. °dONLNdn`lÁ**Attaching this palette to the window will °dONLNdò`Ál⁄)œ-cause the correct remapping to occur when you°dONLNdΔlxñ(î6MCopyBits from the GWorld to the window, and everything should look just fine.
  6977. °dONLNd    êü¢*'7Why PlotCIcon requires GetCIcon instead of Get1Resource
  6978. °dONLNd    Lü´>* Written:°dONLNd    Uüd´à)L4/26/91 ◊4◊˘
  6979. (Ï624)
  6980.  of 29(ÏîColor QuickDraw Q&Asˇ ◊#ˇ ˇˇˇˇ#◊ 
  6981. IR,Times
  6982. .+Z-Developer Support Center(-Ê October 1992 /X/
  6983. °dONLNd<)Å(EZLast reviewed:°dONLNdà)¨)L6/17/91°dONLNd5<A§(]ZWhy do I have to use °dONLNd,5§A˛)hEGetCIcon(resID) instead of Get1Resource('cicn',resID) forPlotCIcon to°dONLNdrA<MÜ(iZwork correctly?°dONLNdÇM<YN* ___°dONLNdÜe<qS*You °dONLNdäeSq˛)[apparently thought something that, at first, I thought also: that GetCIcon(resID) is just a°dONLNdÊq<}ô(ôZHutility routine that translates to Get1Resource('cicn',resID). However, °dONLNd.qô}˛(ô∑this is not the case;°dONLNdD}<â/(•Z3GetCIcon not only gets the 'cicn' resource, but it °dONLNdw}/â˛)Û'also performs some minor surgery on the°dONLNdüâ<ïı(±Z*results, fills in some placeholder fields °dONLNd…âıï˛)π8in the resource data, and the like. Basically, PlotCIcon°dONLNdï<°)(ΩZ1can’t work without the things that GetCIcon does.
  6984. °dONLNd4π<»‹*';CopyBits maps source PixMap colors to GDevice inverse table
  6985. °dONLNdp»<‘b* Written:°dONLNdy»à‘¶)L4/3/91°dONLNdÄ‘<‡Å(¸ZLast reviewed:°dONLNdè‘à‡¨)L6/17/91°dONLNdóÏ<¯¨(ZI’m trying to draw off °dONLNdÆÏ¨¯˛)p?screen so I made my own CGrafPort, PixMap, and color table, but°dONLNdÓ¯<õ( ZIwhen I draw into it, the colors come out all wrong. What’s going on here?°dONLNd8<N* ___°dONLNd<<(£*It’s a very common °dONLNdO£(˛)gCmisconception that CopyBits maps the colors available in the source°dONLNdì(<4√(PZUPixMap’s color table to the colors available in the destination PixMap’s color table.°dONLNdÈ@<L˛*'What actually happens is that CopyBits °dONLNd@˛L˛)¬2maps the colors in the source PixMap to the colors°dONLNdCL<Xt(tZ
  6986. available in °dONLNdPLtX˛)8Nthe current GDevice’s inverse table. See Inside Macintosh, Volume V, pages 137°dONLNdüX<da(ÄZ@through 139 for a description of inverse tables. Inverse tables °dONLNdflXad˛(Ä is a backwards color table. With°dONLNdd<p(åZ1a color table, you use a pixel value as an index °dONLNd1dp˛)fi1into the table to return a color. With an inverse°dONLNdcp<|6(òZ3table, you use a color-like value as an index into °dONLNdñp6|˛)˙'the table to return a pixel value. When°dONLNdæ|<àò(§ZFCopyBits maps colors from one pixel map to another, it takes a source °dONLNd|òà˛(§∂pixel value, uses the°dONLNdà<îø(∞ZSsource PixMap’s color table to get the corresponding color, and uses that color as °dONLNdmàøî˛(∞›
  6987. an index into°dONLNd{î<†(ºZ'the current GDevice’s inverse table to °dONLNd¢î†˛)¥;get the pixel value of the closest color in the destination°dONLNdfi†<¨¢(»ZPixMap’s color table.°dONLNdÙ∏<ƒ)*2Generally speaking, every conceivable color table °dONLNd&∏)ƒ˛)Ì-has exactly one conceivable inverse table. If°dONLNdTƒ<–∞(ÏZyou alter the contents of °dONLNdnƒ∞–˛)tIa color table, then the inverse table must likewise be altered. It’s just°dONLNd∏–<‹∂(¯ZOlike numbers: for any number you give me, I can give you its negative. For any °dONLNd–∂‹˛(¯‘color table you°dONLNd‹<ËÓ(Z!give me, MakeITable can give you °dONLNd8‹Ó˲)≤5its inverse table. MakeITable is documented in Inside°dONLNdnË<Ù⁄(ZMacintosh, Volume V, page 142.°dONLNdç< j*    Think of °dONLNdñj ˛).Othe current GDevice as an implied parameter to CopyBits. If you don’t deal with°dONLNdÊ <≤(4ZNGDevices at all, then the current GDevice is always the main screen’s GDevice °dONLNd    4 ≤˛(4–as far as you’re°dONLNd    E<$ë(@Zconcerned. Color °dONLNd    Vë$˛)UHQuickDraw often switches between different screens’ GDevices so that you°dONLNd    ü$<0(LZ-can draw to multiple screens, but that’s all °dONLNd    Ã$0˛) 1handled behind your back. If you create a PixMap,°dONLNd    ˛0<<;(XZ9give it a color table, and CopyBits to it, then the main °dONLNd
  6988. 70;<˛)ˇ(screen’s GDevice’s inverse table is used°dONLNd
  6989. `<<H(dZ-to map colors from the source PixMap. That’s °dONLNd
  6990. ç<H˛)›-OK as long as your destination PixMap’s color°dONLNd
  6991. ªH<TU(pZtable °dONLNd
  6992. ¡HUT˛)Xis compatible with the main screen’s inverse table. If you change the depth and/or color°dONLNd T<`›(|Z#table of the main screen, and then °dONLNd =T›`˛)°:still CopyBits to this same PixMap with the same old depth°dONLNd x`<lN(àZ:and color table, then things won’t work correctly because °dONLNd ≤`Nl˛(àl#the main screen’s GDevice’s inverse°dONLNd ÷l<x±(îZtable changes, making °dONLNd Ïl±x˛)u@it incompatible with your destination PixMap’s color table. This°dONLNd -x<Ñ∞(†ZSproblem usually manifests itself as incorrect colors, but it can result in crashes.°dONLNd Åê<ú‚*YTo fix this, you’ll have to remove your reliance on the main screen’s GDevice.To do that °dONLNd ⁄ê‚ú˛(∏you’ll°dONLNd ·ú<®}(ƒZ
  6993. have to make °dONLNd Óú}®˛)AJyour own GDevice. There’s a routine called NewGDevice, but it always makes ◊X◊
  6994. (ÏZColor QuickDraw Q&As(Ï˙25)
  6995.  of 29ˇƒ◊#ˇ ˇˇˇˇ#◊ 
  6996. IR,Times
  6997. .+6-Macintosh Technical Notes /4/˘
  6998. °dONLNd)±*Vthe GDevice in the system heap. Instead, you should just call NewHandle to allocate a °dONLNdV±)⁄(EœGDevice°dONLNd^)5
  6999. (Q64record yourself. Here’s what the fields should hold:°dONLNdìAM3*:gdRefNum - The GDevice has no driver, so set this to zero.°dONLNdŒYem*LgdID - It doesn’t matter what this is set to — might as well set it to zero.°dONLNdq}»*bgdType - Set this to 2 if the off-screen uses direct colors (16 or 32 bits per pixel) or 0 if the °dONLNd}q»}÷(ôÊoff°dONLNdÄq÷}⁄)-°dONLNdÅ}â(•67screen uses a color table (1 through 8 bits per pixel).°dONLNdπï°†*VgdITable - Allocate a small (maybe just a 2-byte) handle for this field. After you’re °dONLNd⁄(Ωæ done setting°dONLNd°≠Û(…6,up this GDevice and your off-screen PixMap, °dONLNdH°Û≠⁄)€1color table (if any) and CGrafPort, then set this°dONLNdz≠π¡(’6"GDevice as the current GDevice by °dONLNdú≠¡π⁄)©8calling SetGDevice. Then call MakeITable, passing it NIL°dONLNd’π≈k(·6Efor both the color table and inverse table parameters, and 0 for the °dONLNdπk≈⁄(·âpreferred inverse table°dONLNd2≈—K(Ì6 resolution.°dONLNd>›È*2gdResPref - I’d guess that more than 99.9% of all °dONLNdp›È⁄)Ô-inverse tables out there have a resolution of°dONLNdûÈıf(6C4. Unless you have some reason not to, I’d recommend the same here.°dONLNd‚
  7000. Ñ*IgdSearchProc - Set to NIL. Use AddSearch if you want to use a SearchProc.°dONLNd,%{*CgdCompProc - Set to NIL. Use AddComp if you want to use a CompProc.°dONLNdp1=≠*"gdFlags - Set to 0 initially, and °dONLNdí1≠=⁄)ï@then use SetDeviceAttribute after you’ve set up the rest of this°dONLNd”=IE(e6GDevice.°dONLNd‹Ua5*;gdPMap - Set this to be a handle to your off-screen PixMap.°dONLNdmy„*)gdRefCon - Set this to whatever you want.°dONLNdBÖëò*gdNextGD - Set this to nil.°dONLNd^ù©O*AgdRect - Set this to be equal to your off-screen PixMap’s bounds.°dONLNd†µ¡Å*KgdMode - Set this to -1. This is intended for GDevices with drivers anyway.°dONLNdÏÕŸÅ*gdCCBytes - Set to 0.°dONLNdÂÒÇ*gdCCDepth - Set to 0.°dONLNd˝    Ñ*gdCCXData - Set to 0.°dONLNd.!â*gdCCXMask - Set to 0.°dONLNdD-9Ç*gdReserved - Set to 0.°dONLNd[EQ§*For gdFlags, you should use °dONLNdwE§Q⁄)å@SetDeviceAttribute to set the noDriver bit and the gDevType bit.°dONLNd∏Q]ª(y6VYou should set the gDevType bit to 1 even if you have a monochrome color table. The 0 °dONLNdQª]⁄(yŸsetting°dONLNd]ià(Ö6was only used when °dONLNd)]ài⁄)p;monochrome mode was handled by the video driver, and 32-Bit°dONLNdeiu©(ë6PQuickDraw eliminated that convention. Your GDevice doesn’t have a driver anyway.°dONLNd∂Åç⁄*'Once this is done, the GDevice and the °dONLNd›Å⁄ç⁄)¬3off-screen PixMap should be treated as inseparable.°dONLNdçôæ(µ6 When you CopyBits or draws into °dONLNd1çæô⁄)¶;the PixMap, first call SetGDevice to set its GDevice as the ◊4◊˘
  7001. (Ï626)
  7002.  of 29(ÏîColor QuickDraw Q&Asˇn◊#ˇ ˇˇˇˇ#◊ 
  7003. IR,Times
  7004. .+Z-Developer Support Center(-Ê October 1992 /X/
  7005. °dONLNd<)Ø(EZKcurrent GDevice. When that’s done, call SetGDevice to restore the previous °dONLNdKØ)˛(EÕGDevice. Doing°dONLNdZ)<5?(QZ6this insulates you from changes in a screen’s GDevice.°dONLNdëA<MS*8If you alter your PixMap’s color table, you should make °dONLNd…ASM˛(iq"sure you update the ctSeed of that°dONLNdÏM<YX(uZcolor °dONLNdÚMXY˛)Stable, either by assigning to it the result of GetCTSeed (documented on page 143 of°dONLNdFY<eº(ÅZInside Macintosh, Volume °dONLNd_Yºe˛)Ä@V) or by passing a handle to the color table to CTabChanged. The°dONLNd†e<q∂(çZnext time that PixMap is °dONLNdπe∂q˛)z>drawn into, Color QuickDraw will update your GDevice’s inverse°dONLNd¯q<}y(ôZGtable automatically when it realizes that the ctSeed is different from °dONLNd?qy}˛(ôóthe current GDevice (which°dONLNdZ}<â(•Z.had better be yours) inverse table’s iTabSeed.°dONLNdâï<°j*9GWorlds work this way on Color QuickDraw machines. Every °dONLNd¬ïj°˛(ΩàGWorld comes with a PixMap°dONLNd›°<≠Ù(…ZRand a GDevice. When you call SetGWorld, that sets both the GWorld and its GDevice °dONLNd/°Ù≠˛(…as°dONLNd2≠<πa(’Zcurrent.
  7006. °dONLNd;—<‡u*',How Macintosh system draws small color icons
  7007. °dONLNdh‡<Ïb* Written:°dONLNdq‡àϨ)L3/31/92°dONLNdyÏ<¯Å(ZLast reviewed:°dONLNdàÏ௨)L5/21/92°dONLNdê<“(,ZTThe code I added to my application’s MDEF to plot small icons in color works except °dONLNd‰“˛(,for when°dONLNdÌ<Ô(8ZXI hold the mouse over an item with color. The color of the small icons is wrong because °dONLNdEÔ˛(8
  7008. it’s°dONLNdJ<(⁄(DZ!just doing an InvertRect. When I °dONLNdk⁄(˛)û:drag over the Apple menu, the menu inverts behind the icon°dONLNd¶(<4‡(PZ#but the icon is untouched. Is this °dONLNd…(‡4˛)§9done by brute force, redrawing the small icon after every°dONLNd4<@r(\Z InvertRect?°dONLNd@<LN* ___°dONLNdX<dí*DAs you figured out, the Macintosh system draws color icons, such as °dONLNdWXíd˛(Ä∞the Apple icon on the°dONLNdmd<p(åZ2menu bar, every time the title has to be inverted.°dONLNd†|<à¬*The actual sequence of calls °dONLNdΩ|¬à˛)ÜEis (more or less) as follows: first InvertRect is called to black the°dONLNdà<îY(∞Zmenu °dONLNdàYî˛)Ytitle and then PlotIconID is called to draw the icon in its place. The advantage of using°dONLNdbî<†Œ(ºZVPlotIconID is that you don’t have to worry about the depth and size of the icon being °dONLNd∏˛(ºÏ    used. The°dONLNd¬†<¨.(»Z,system picks the best match from the family °dONLNdÓ†.¨˛)Ú%whose ID is being passed, taking into°dONLNd¨<∏(‘Zconsideration °dONLNd"¨∏˛)CPthe target rectangle and the depth of the device(s) that will contain the icon’s°dONLNds∏<ƒ\(‡Zimage.°dONLNdz–<‹H*8The Icon Utilities call PlotIconID is documented in the °dONLNd≤–H‹˛(¯f"Macintosh Technical Note, “Drawing°dONLNd’‹<Ë‚(ZZIcons the System 7 Way.” Just in case you don’t have your stack at hand, the interface is:,
  7009. Courier
  7010.     °dONLNd0Ù<ˇ˙*&    IconAlignmentType    =    INTEGER;°dONLNdW˛<    ˙*
  7011. &    IconTransformType    =    INTEGER;°dONLNd~<˙*&    FUNCTION PlotIconID(theRect: Rect;°dONLNd•<'1*
  7012. 1                        align: IconAlignmentType;°dONLNd◊&<1E*
  7013. 5                        transform: IconTransformType;°dONLNd    
  7014. 0<;6*
  7015. 2                        theResID: INTEGER): OSErr;°dONLNd    @:<E˙*
  7016. &        INLINE    $303C, $0500, $ABC9;°dONLNd    lN<YÎ*#typedef short    IconAlignmentType;°dONLNd    êX<cÎ*
  7017. #typedef short    IconTransformType;°dONLNd    ¥l<w*,pascal OSErr PlotIconID(const Rect *theRect,°dONLNd    ·v<Å@*
  7018. 4                            IconAlignmentType align,°dONLNd
  7019. Ä<ãT*
  7020. 8                            IconTransformType transform,°dONLNd
  7021. Oä<ï*
  7022. +                            short theResID)°dONLNd
  7023. {î<ü◊*
  7024.     = {0x303C, 0x0500, 0xABC9}; ◊X◊
  7025. *1Color QuickDraw Q&As(Ï˙27)
  7026.  of 29ˇ»◊#ˇ ˇˇˇˇ#◊ 
  7027. IR,Times
  7028. .+6-Macintosh Technical Notes /4/˘
  7029. °dONLNd)ô*SPlease refer to the Tech Note referenced above for more details on using the calls.
  7030. °dONLNdTAP∞*'8Spooling and preserving Macintosh QuickDraw pixmap depth"`3
  7031. °dONLNdçP\>* Written:°dONLNdñPd\à)L2/11/92"o3 °dONLNdû\h](Ñ6Last reviewed:°dONLNd≠\dhà)L9/15/92"{3 "á3 °dONLNdµtÄ(ú66When spooling a picture that contains a PixMap into a °dONLNdÎtÄ⁄(ú7$window, how and when is the depth of"ì3 °dONLNdÄåó(®6Qthe PixMap in the picture converted to the depth of the screens the window is on?"ü3 °dONLNdbåò** ___"´3 "∑3 °dONLNdf§∞®*When spooling in a picture, if °dONLNdÖ§®∞⁄)ê<QuickDraw encounters any bitmap opcode it allocates a pixmap"√3 °dONLNd¬∞ºÃ(ÿ6Wof the same depth as the data contained in the bitmap opcode, it expands the data into °dONLNd∞ú⁄(ÿÍthe"œ3 °dONLNdº»˘(‰6-temporary pixmap, and then it calls StdBits. °dONLNdJº˘»⁄)·,StdBits is what triggers the depth and color"€3 °dONLNdw»‘a(6conversions as °dONLNdÜ»a‘⁄)IKdemanded by the color environment (depth, color table, B&W settings) of the"Á3 °dONLNd“‘‡†(¸6Pdevices the target port may span (as when a window crosses two or more screens)."Û3 "ˇ3 °dONLNd#ϯÜ*If there’s not enough °dONLNd9Ïܯ⁄)n?memory in the application heap or in the temporary memory pool," 3 °dONLNdy¯†( 6QuickDraw bands the image °dONLNd쯆⁄)àAdown to one scan line and calls StdBits for each of these pieces."3 °dONLNd’Ÿ(,6`Note that if you’re providing your own bits proc then QuickDraw will call it instead of StdBits."#3 "/3 °dONLNd6(º*"This process is the same when the °dONLNdXº(⁄)§:PICT is in memory, with the obvious exception that all the";3 °dONLNdì(4ê(P6PPICT data are present; all the color mapping occurs when StdBits does its stuff."G3 
  7032. °dONLNd‰L[*'$Determining the resolution of a PICT"k3
  7033. °dONLNd    [g>* Written:°dONLNd[dgà)L6/10/92"z3 °dONLNdgs](è6Last reviewed:°dONLNd)gdsà)L9/15/92"Ü3 "í3 °dONLNd1ã[(ß6EIn a version 2 picture, the picFrame is the rectangular bounding box °dONLNdv[ã⁄(ßyof the picture, at 72 dpi. I"û3 °dONLNdìãóõ(≥6would like to determine the °dONLNdØãõó⁄)ÉEbounding rectangle at the stored resolution or the resolution itself."™3 °dONLNdıó£ó(ø6SIs there a way to do this without reading the raw data of the PICT resource itself?"∂3 °dONLNdI£Ø** ___"¬3 "Œ3 °dONLNdMª«Ã*%With regular version 2 PICTs (or any °dONLNdrªÃ«⁄)¥:pictures), figuring out the real resolution of the PICT is"⁄3 °dONLNd≠«”©(Ô6pretty tough. Applications use °dONLNdë©”⁄)ë?different techniques to save the information. But if you make a"Ê3 °dONLNd ”fl≠(˚6picture with OpenCPicture, the °dONLNd+”≠fl⁄)ï>resolution information is stored in the headerOp data, and you"Ú3 °dONLNdjflÎ(65can get at this by searching for the headerOp opcode °dONLNdüflÎ⁄)˘+in the picture data (it’s always the second"˛3 °dONLNdÀΘ(69opcode in the picture data, but you still have to search °dONLNdΘ⁄(6)for it in case there are any zero opcodes"
  7034. 3 °dONLNd.˜ò(6Ubefore it). Or you can use the Picture Utilities Package to extract this information."3 ""3 °dONLNdÑ*8With older picture formats, the resolution and original °dONLNdº⁄(77&bounds information is sometimes not as".3 °dONLNd„'o(C6obvious or easily °dONLNdıo'⁄)WJderived. In fact, in some applications, the PICT’s resolution and original":3 °dONLNd    @'3 (O66bounds aren’t stored in the header, but rather in the °dONLNd    v' 3⁄)Ù+pixel map structure(s) contained within the"F3 °dONLNd    ¢3?6([6PICT."R3 "^3 °dONLNd    ®KWñ*NTo examine these pixMaps, you’ll first need to install your own bitsProc, and °dONLNd    ˆKñW⁄(s¥
  7035. then manually"j3 °dONLNd
  7036. Wc$(66check the bounds, hRes, and vRes fields of any pixMap °dONLNd
  7037. :W$c⁄(B$being passed. In most cases the hRes"v3 °dONLNd
  7038. _co¡(ã6Mand vRes fields will be set to the Fixed value 0x00480000 (72 dpi); however, °dONLNd
  7039. ¨c¡o⁄(ãflsome"Ç3 °dONLNd
  7040. ±o{Œ(ó6_applications will set these fields to the PICT’s actual resolution, as shown in the code below."é3 "ö3 ,
  7041. Courier
  7042.     °dONLNd áí§*Rect            gPictBounds;"¶3    °dONLNd .ëú÷*
  7043. &Fixed            gPictHRes, gPictVRes;"∞3    "∫3     ◊4◊˘
  7044. *428)
  7045.  of 29(ÏîColor QuickDraw Q&Asˇñ◊#ˇ ˇˇˇˇ#◊ 
  7046. IR,Times
  7047. .+Z-Developer Support Center(-Ê October 1992 /X/,
  7048. Courier
  7049.     °dONLNd<(c(DZ;pascal void ColorBitsProc (srcBits, srcRect, dstRect, mode,"<W    °dONLNd='<2x*
  7050.     maskRgn)"FW    °dONLNdJ1<<Ø*
  7051. BitMap        *srcBits;"PW    °dONLNdb;<FÎ*
  7052. #Rect            *srcRect, *dstRect;"ZW    °dONLNdÜE<P™*
  7053. short            mode;"dW    °dONLNdùO<Z•*
  7054. RgnHandle    maskRgn;"nW    °dONLNd≥Y<dA*
  7055. {"xW    °dONLNdµc<n†*
  7056.     PixMapPtr    pm;"ÇW    °dONLNd m<x»*
  7057.     pm = (PixMapPtr)srcBits;"åW    °dONLNdÁw<Ç◊*
  7058.     gPictBounds = (*pm).bounds;"ñW    °dONLNdÅ<å@*
  7059. 4    gPictHRes = (*pm).hRes;        /* Fixed value */"†W    °dONLNd<ã<ñ@*
  7060. 4    gPictVRes = (*pm).vRes;        /* Fixed value */"™W    °dONLNdqï<†A*
  7061. }"¥W    °dONLNdsü<™æ*
  7062. void FindPictInfo(picture)"æW    °dONLNdé©<¥ñ*
  7063. PicHandle picture;"»W    °dONLNd°≥<æA*
  7064. {"“W    °dONLNd£Ω<»‹*
  7065.      CQDProcs        bottlenecks;"‹W    °dONLNdƒ«<“‹*
  7066.      SetStdCProcs (&bottlenecks);"ÊW    °dONLNd—<‹"*
  7067. .    bottlenecks.bitsProc = (Ptr)ColorBitsProc;"W    °dONLNd€<ÊT*
  7068. 8    (*(qd.thePort)).grafProcs = (QDProcs *)&bottlenecks;"˙W    °dONLNdMÂ<;*
  7069. 3    DrawPicture (picture, &((**picture).picFrame));"W    °dONLNdÅÔ<˙Î*
  7070. #    (*(qd.thePort)).grafProcs = 0L;"W    °dONLNd•˘<A*
  7071. }"W     ◊X◊
  7072. (ÏZColor QuickDraw Q&As(Ï˙29)
  7073.  of 29ˇr◊#ˇ ˇˇˇˇ#◊†Ç 
  7074. /ZÅ#
  7075.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  7076. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  7077. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  7078. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  7079. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  7080.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  7081. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  7082. IR.°dONLNdz<ç,(ßZAdding Color With CopyBits
  7083. °dONLNdå<õr*Imaging°dONLNd#årõ˛(∑êM.IM.ColorCopyBits
  7084. °dONLNd6ß<≥q(œZ
  7085. Revised by°dONLNdBß≈≥˛(œ„
  7086. March 1988°dONLNdM≥<øq(€Z Written by:°dONLNdY≥Ñø≈)H
  7087. Chris Derossi°dONLNdg≥±ø˛(€œ
  7088. November 1987°dONLNduÀ<◊¿(ÛZInside Macintosh Volume V°dONLNdéÀ¿◊Q)Ñ  states that the foreground and °dONLNdÆÀQ◊˛)ë#background colors are applied to an°dONLNd“ÿ<‰Ö(Zimage during a ,
  7089. Courier°dONLNd·◊Ö„Ω)ICopyBits°dONLNdÈÿΩ‰Õ)8 or °dONLNdÌ◊Õ„)CopyMask°dONLNdıÿ‰á)8 call. Accidental use of this °dONLNdÿቲ)Çfeature can create bizarre°dONLNd.‰<ˆ( Z\coloring effects. This note explains what happens, how to avoid problems, and how to use it. X
  7090. °dONLNdã<$ô*4 What Happens
  7091. °dONLNdò0<<Æ*Color QuickDraw has a °dONLNdÆ0Æ<˛)rDfeature that will allow you to convert a monochrome image to a color°dONLNdÛ=<Iã(eZimage. During a °dONLNd<ãH√)OCopyBits°dONLNd =√IΔ)8 °dONLNd =ΔI‘)or °dONLNd<‘H )CopyMask°dONLNd= I˛)82 call, if the foreground and background colors are°dONLNdJI<U‘(qZTnot black and white, respectively, Color QuickDraw performs the following operation °dONLNdûI‘U˛(qÚon every°dONLNdßU<aï(}Zpixel being copied:
  7092.     °dONLNdºn`y+$%NOTE: color table index = pixel value°dONLNd„Ç`ç*%s = color table index of source pixel°dONLNd
  7093. å`ó2*
  7094. *fg = color table index of foreground color°dONLNd6ñ`°2*
  7095. *bg = color table index of background color°dONLNdb™`µU*1ColoredPixelValue = (NOT(s) AND bg) OR (s AND fg)
  7096. °dONLNdî¿<Ã0(ËZ3If your source image contains only black and white °dONLNd«¿0Ã˛)Ù*pixels, then all black pixels would become°dONLNdÚÃ<ÿF(ÙZ7the foreground color and all white pixels would become °dONLNd)ÃFÿ˛(Ùd%the background color. This is because°dONLNdOÿ<‰◊(Z]the color table index for white is all zeros and the color table index for black is all ones.°dONLNd≠Ò<˝m*>For example, suppose your source image was a 4-bit deep color °dONLNdÎm¸ó(ãPixMap°dONLNdÒÒó˝û)*. °dONLNdÛÒû˝˛)Then the color table°dONLNd˝<    ”(%ZWindex for white (in binary) is 0000 and the index for black is 1111. And let’s suppose °dONLNd_˝”    ˛(%Ò    that your°dONLNdi    <Û(1ZXforeground color is green with an index of 1101 while your background color is red with °dONLNd¡    Û˛(1an°dONLNdƒ<!ë(=ZGindex of 0011. Then for the black pixels, the above procedure produces:
  7097.     °dONLNd
  7098. -`8á+$;ColoredPixelValue = (NOT(1111) AND 0011) OR (1111 AND 1101)°dONLNdJ7`Bá*
  7099. ;     1101         = (  0000    AND 0011) OR (1111 AND 1101)
  7100. °dONLNdÜM<Y(uZ-And the operation on the white pixels yields:
  7101.     °dONLNdµf`qá+$;ColoredPixelValue = (NOT(0000) AND 0011) OR (0000 AND 1101)°dONLNdÚp`{á*
  7102. ;     0011         = (  1111    AND 0011) OR (0000 AND 1101)
  7103. °dONLNd.í<°µ(ΩZPossible Problems ◊X◊
  7104. */Adding Color With CopyBits(Ï1) of 3ˇ°¿Ù%%DSIDICT:_cv
  7105. currentdict /bu known {bu}if
  7106. userdict /_cv known not{userdict /_cv 30 dict put}if
  7107. _cv begin
  7108. /bdf{bind def}bind def
  7109. currentscreen/cs exch def/ca exch def/cf exch def
  7110. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  7111. /ss{//cf //ca //cs setscreen}bdf
  7112. /stg{ss setgray}bdf
  7113. /strgb{ss setrgbcolor}bdf
  7114. /stcmyk{ss cvcmyk}bdf
  7115. /min1{dup 0 eq{pop 1}if}bdf
  7116. end
  7117. currentdict /bn known {bn}if
  7118. †ø⁄◊#ˇ ˇˇˇˇ#◊ 
  7119. IR,Times
  7120. .+6-Macintosh Technical Notes /4/˘
  7121. °dONLNd)G*AThis colorizing will only work on 2-color (i.e. black and white) °dONLNdAG)⁄(Eeimages, and then only if those°dONLNd`)5Ñ(Q6colors occupy the first °dONLNdx)Ñ5⁄)lKand last entries in the color table. Trying to colorize colors that are not°dONLNdƒ5AF(]6Ethe first and last color table entries will yield unexpected results.°dONLNd
  7122. MYm*LThis is mainly due to the fact that the colorizing algorithm uses a pixel’s °dONLNdVMmY⁄(uãcolor table index value°dONLNdnYe(Å60rather than its actual RGB color. To illustrate °dONLNdûYe⁄)˜&this, let’s assume that foreground and°dONLNd≈eqy(ç6Fbackground colors are as above, and your image contains yellow with a °dONLNd eyq⁄(çócolor table index of°dONLNd q}Â(ô6*1000. The colorizing operation would give:,
  7123. Courier
  7124.     °dONLNdLâ<îc+$;ColoredPixelValue = (NOT(1000) AND 0011) OR (1000 AND 1101)°dONLNdâì<ûc*
  7125. ;     1011         = (  0111    AND 0011) OR (1000 AND 1101)
  7126. °dONLNd≈©µï(—6NSince the color table may have any RGB color at the resulting index position, °dONLNd©ïµ⁄(—≥the final color°dONLNd#µ¡k(›6Fmay not even be close to the source, foreground, or background colors.°dONLNdjÕŸé*PSimilar things occur if you are trying to colorize a black and white image when °dONLNd∫ÕéŸ⁄(ı¨white and black°dONLNd ŸÂ,(6>do not occupy the first and last positions in the color table.°dONLNd    Ú˛ê*The bottom line rules for °dONLNd#Òê˝»)xCopyBits°dONLNd+Ú»˛s)8%ing in a color environment are these:°dONLNdQ
  7127. *.(2H•°dONLNdS
  7128. 7º)
  7129. OThou shalt set thy background color to white and thy foreground color to black °dONLNd¢
  7130. º⁄(2⁄before°dONLNd©7#Y(?Ucalling °dONLNd±Y"ë)"CopyBits°dONLNdπë#°)8 or °dONLNdΩ°"Ÿ)CopyMask°dONLNd≈Ÿ#ª)8., unless thou art coloring a monochrome image.°dONLNdÙ/*;.(WH•°dONLNdˆ/7;∂)
  7131. QThou shalt, when colorizing, make sure that the first color table entry is white °dONLNdG/∂;⁄(W‘and the°dONLNdO;7GJ(cUlast °dONLNdU;`G◊))color table entry is black.°dONLNdqS_.({6<The second rule is easy to follow because the default color °dONLNd≠S._⁄({L$tables are constructed properly, and°dONLNd“_kv(á6if you are using the °dONLNdÁ_vk⁄)^KPalette Manager (and you are, right?) then it will make sure that the color°dONLNd3kwz(ì6tables obey this rule.
  7132. °dONLNdJèûÍ*'How To Colorize—An Example
  7133. °dONLNde™∂ò*This code fragment shows °dONLNd~™ò∂⁄)ÄDhow to implement a color fill, like the paint bucket in MacPaint. It°dONLNd√∑√ü(fl6relies on three main things: °dONLNd‡∂ü¬fi)á    SeedCFill°dONLNdÈ∑fi√h)?  for calculating the fill area, °dONLNd    ∂h¬†)äCopyMask°dONLNd∑†√∂)8 for °dONLNd∑∂√⁄)actually°dONLNd√œÔ(Î6,changing the bits, and QuickDraw colorizing.
  7134.     °dONLNdL€Ê:*:PROCEDURE PaintBucket(where: Point; paintColor: RGBColor);°dONLNdàÔ<˙K+$VAR°dONLNdé˘`É+$
  7135. savedFG°dONLNdñ˘®fl)H : RGBColor;°dONLNd§`É(*~offBits°dONLNd¨®’)H    : BitMap;°dONLNd∑<"U(>ZBEGIN°dONLNdø!`,+$
  7136. ${First, create an offscreen bitmap.}°dONLNdÊ+`6*
  7137. %offBits.bounds := myWindow^.portRect;°dONLNd5`@Ï*
  7138. WITH offBits.bounds DO BEGIN°dONLNd.?ÑJç+$
  7139. 5offBits.rowBytes := ((right - left + 15) DIV 16) * 2;°dONLNdgIÑT∞*
  7140. <offBits.baseAddr := NewPtr((bottom-top) * offBits.rowBytes);°dONLNd¶S`^t(z~END;°dONLNd≠g`rZ*2{Check MemError here! Make sure NewPtr succeeded!}°dONLNd‚{`Üx*8SeedCFill(myWindow^.portBits,offBits,myWindow^.portRect,°dONLNd    ÖÑêV+$
  7141. *myWindow^.portRect,where.h,where.v,NIL,0);°dONLNd    Kè`öŒ(∂~GetForeColor(savedFG);°dONLNd    dô`§›*
  7142. RGBForeColor(paintColor);°dONLNd    Ä£`Æõ*
  7143. ?CopyMask(offBits,offBits,myWindow^.portBits,myWindow^.portRect, ◊4◊˘
  7144. (Ï62) of 3(ÏÇAdding Color With CopyBitsˇ*◊#ˇ ˇˇˇˇ#◊ 
  7145. IR,Times
  7146. .+Z-Developer Support Center(-Ï
  7147. March 1988 /X/,
  7148. Courier
  7149.     °dONLNd®(k(DΔ'myWindow^.portRect,myWindow^.portRect);°dONLNd*'Ñ2Ú(N¢RGBForeColor(savedFG);°dONLNdC;ÑF*DisposPtr(offBits.BaseAddr);°dONLNdaE`Pt(l~END;
  7150. °dONLNdf\<hÉ(ÑZ
  7151. The variable °dONLNds[Ég¥)GoffBits°dONLNdz\¥h)1 is an offscreen °dONLNdã[g=)_BitMap°dONLNdë\=hE)* °dONLNdí\Eho)(not a °dONLNdô[ogô)*PixMap°dONLNdü\ôhƒ)*) with °dONLNd¶[ƒgÓ)+bounds°dONLNd¨\Óh˛)* =°dONLNdØh<t∫(ëZmyWindow^.portRect°dONLNd¡i∫u»)~.  °dONLNdƒh»t)    SeedCFill°dONLNdÕiuy)? effectively creates, in °dONLNdÊiyuø)rthe offscreen °dONLNdÙhøtÈ)FBitMap°dONLNd˙iÈu˛)*,  a°dONLNdˇv<Ç_(ûZ:monochrome image of the bits that we want to paint. Since °dONLNd9u_Åê(û}offBits°dONLNd@vêÇÌ)1 contains the exact °dONLNdTvÌDz)]bits°dONLNdYÉ<èõ(´ZLthat we want to paint, it is used as both the source image and the mask for °dONLNd•Çõé”(´πCopyMask°dONLNd≠É”è◊)8.°dONLNdØõ<ß(√ZaBy setting the foreground color to the desired paint color, the result is a colorized version of °dONLNdõ߲(√the°dONLNd®<¥•(–Zmask (the paint area) °dONLNd*®•¥J)ibeing copied onto the window’s °dONLNdIßJ≥t)•PixMap°dONLNdO®t¥˛)* without affecting any other°dONLNdl¥<¿Q(‹Zbits.°dONLNdr‰<¶*0Further Reference: X°dONLNdÖÒN˝R+
  7152. •°dONLNdáÒ`˝¥)Color QuickDraw ◊X◊
  7153. (ÏZAdding Color With CopyBits(Ï3) of 3ˇÍ◊#ˇ ˇˇˇˇ#◊°d WORDS †å°d WORDR…†Ç 
  7154. /ZÅ#
  7155.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  7156. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  7157. .^ tK^ tK+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  7158. Ä({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  7159. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  7160.     l+&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  7161. BÄ(Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É°dWORD†ç
  7162. IR.°dONLNd{<éœ(®Z+Deaccelerated _CopyBits & 8•24 GC QuickDraw
  7163. °dONLNd,ç<úr*Imaging°dONLNd4çoú˛(∏çM.IM.GCQDCopybits
  7164. °dONLNdF®<¥q(–Z Written by:°dONLNdR®Ñ¥›)HGuillermo A. Ortiz°dONLNde®∏¥˛(–÷
  7165. February 1991°dONLNds¡<Õ“(ÈZThis Technical Note discusses °dONLNdë¡“ÕV)ñconditions that may cause ,
  7166. Courier°dONLNd´¿VÃï)Ñ    _CopyBits°dONLNd¥¡ïÕ˛)? to slow down when°dONLNd«Õ<Ÿy(ıZ@QuickDraw acceleration is on via the Apple 8•24 GC Display Card. X
  7167. °dONLNd˛<
  7168. è*4 Introduction
  7169. °dONLNd<%ç*CWhen a drawing call is issued, GC IPC (Interprocess Communication) °dONLNdXç%˛(A´takes control of the call°dONLNdr%<1`(MZ=and passes it to GC QuickDraw.  After the normal port set up °dONLNdØ%`1˛(M~ (which involves caching the port°dONLNd–1<=›(YZ[parameters if this is the first drawing call after the port was set), GC QuickDraw returns °dONLNd+1›=˛(Y˚control°dONLNd3=<IY(eZ>to the application through the IPC and performs, in parallel, °dONLNdq=YI˛(ew!the drawing to its own monitor as°dONLNdìI<Uı(qZ$well as any other monitors that may °dONLNd∑IıU˛)π4be affected by  the operation.  The application then°dONLNdÏU<a“(}ZRcontinues its execution, probably issuing more drawing calls that get executed in °dONLNd>U“a˛(}the same°dONLNdGa<m®(âZasynchronous manner.°dONLNd\y<Ö›*YThe result of this mode of operation is improved performance, since the application gets °dONLNdµy›Ö˛(°˚control°dONLNdΩÖ<ë(≠Z0back immediately after issuing the call and the °dONLNdÌÖë˛)„(GC QuickDraw moves video data to its own°dONLNdë<ù1(πZ6video buffer as well as that of other cards in a more °dONLNdLë1ù˛)ı)rapid manner by using block transfers and°dONLNdvù<©0(≈Z3without requiring any action by the main processor.
  7170. °dONLNd™¡<–û*'._CopyBits Conforms To The Same Scheme, Except…
  7171. °dONLNdŸ‹<Ë{*    _CopyBits°dONLNd‚›{È)?" conforms to the same operational °dONLNd›È˛)¢-scheme, but there are some instances in which°dONLNd2È<ıâ(Z
  7172. GC QuickDraw °dONLNd?Èâı˛)MRcannot perform the call in parallel; in this cases it is even possible to suffer a°dONLNdíı<¿(Zperformance loss, since the °dONLNdÆı¿˛)Ñ@whole call may have to be completed before control is given back°dONLNdÔ<‚(*ZVto the application and GC QuickDraw has to make calls and access data across the NuBus
  7173.     °dONLNdE‚ Í('™
  7174. °dONLNdFÍÓ+.°dONLNdH<&∏(BZNThe situations that compromise GC QuickDraw parallel operation are as follows:°dONLNdó3N?R+•°dONLNdô3[?)
  7175. "When the destination device has a °dONLNdª2>I)®
  7176. SearchProc°dONLNd≈3I?¬)F installed and the source °dONLNdfl3¬?⁄)ycolor°dONLNdÂ?[Ko(gy:environment is different from the destination environment.°dONLNd!X[d∞*QuickDraw calls °dONLNd1X∞dª)Ua °dONLNd3Wªc)
  7177. SearchProc°dONLNd=Xd⁄)F) whenever the source and destination have°dONLNdgd[p(åy&different depths and when two indexed °dONLNdçdp⁄)¡'pixel maps have different color tables,°dONLNdµp[|˝(òy even though their depths may be °dONLNd’p˝|⁄)¢,identical.  When GC acceleration is enabled,°dONLNd|[àÿ(§ythese conditions cause the °dONLNd|ÿà⁄)}3following two types of behavior, dependent upon the°dONLNdQà[îÆ(∞ysource pixel map: ◊X◊
  7178. (ÏZ+Deaccelerated _CopyBits & 8•24 GC QuickDraw(Ï1) of 2ˇ°¿Ù%%DSIDICT:_cv
  7179. currentdict /bu known {bu}if
  7180. userdict /_cv known not{userdict /_cv 30 dict put}if
  7181. _cv begin
  7182. /bdf{bind def}bind def
  7183. currentscreen/cs exch def/ca exch def/cf exch def
  7184. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  7185. /ss{//cf //ca //cs setscreen}bdf
  7186. /stg{ss setgray}bdf
  7187. /strgb{ss setrgbcolor}bdf
  7188. /stcmyk{ss cvcmyk}bdf
  7189. /min1{dup 0 eq{pop 1}if}bdf
  7190. end
  7191. currentdict /bn known {bn}if
  7192. †øv◊#ˇ ˇˇˇˇ#◊ 
  7193. IR,Times
  7194. .+6-Macintosh Technical Notes /4/˘
  7195. °dONLNd<)@+$•°dONLNdI)2)
  7196. /If the source is an indexed pixel map, then GC °dONLNd12)®)ÈQuickDraw executes the°dONLNdH*I6
  7197. (Rg,part of the setup that involves calling the ,
  7198. Courier°dONLNdt)
  7199. 5P)¡
  7200. SearchProc°dONLNd~*P6ü)F, returns control °dONLNdê*ü6®)Oto°dONLNdì6IB¿(^gthe main processor, then °dONLNd¨6¿B®)w3completes the call in parallel.  The act of calling°dONLNd‡CIO\(kgthe °dONLNd‰B\N¢)
  7201. SearchProc°dONLNdÓC¢O )F before returning control °dONLNdC O®)~makes the call slower than°dONLNd#PI\y(xgwhen no °dONLNd+Oy[ø)0
  7202. SearchProc°dONLNd5Pø\ƒ)F °dONLNd6Pƒ\®).is involved, since parallel operation does not°dONLNde\Ih‚(Ñg occur throughout the whole call.°dONLNdÜt<Ä@(úZ•°dONLNdàtIÄT)
  7203. If °dONLNdãtTÄ®) Cthe source is a direct RGB pixel map, then GC QuickDraw has to call°dONLNdœÅIçZ(©gthe °dONLNd”ÄZå†)
  7204. SearchProc°dONLNd›Å†ç¥)F for °dONLNd‚Å¥ç®)3every pixel that is drawn, and the application does°dONLNdéIöˇ(∂g+not regain control until after the call to °dONLNdAçˇô>)∂    _CopyBits°dONLNdJé>ö°)? has been completed.°dONLNd_ß*≥.(œH•°dONLNdaß7≥u)
  7205. DWhen the source or destination is offscreen and not created using a °dONLNd•¶u≤ü(œìGWorld°dONLNd´ßü≥£)*.°dONLNdÆø7ÀÁ(ÁU"GC QuickDraw has no way to detect °dONLNd–øÁÀ∂)∞*when an application is going to manipulate°dONLNd˚À7◊*(ÛU6a pixel map it has created in memory, so if it has to °dONLNd1À*◊∂)Ûdraw to or copy from such a°dONLNdM◊7„a(UPixMap°dONLNdSÿa‰‘)*, GC QuickDraw has to °dONLNdiÿ‘‰∂)s/complete the operation before returning control°dONLNdô‰7ã( Uto the application.°dONLNdÆ˝7    D*3This behavior is contrary to the case when using a °dONLNd·¸Dn(%bGWorld°dONLNdÁ˝n    ∂)* for offscreen°dONLNdˆ
  7206. 7~(2Uenvironments, °dONLNd
  7207. ~Ë)Gsince in the case of a °dONLNd    Ë)jGWorld°dONLNd!
  7208. ∂)* , GC QuickDraw is alerted by the°dONLNdB7#\(?Ucall to °dONLNdJ\"≈)%_GetPixBaseAddr°dONLNdY≈#É)i' that the application is getting ready °dONLNdÄÉ#∂)æ to directly°dONLNdå#7/    (KU.change the pixels.  This is the reason why it °dONLNd∫#    /∂)“&is so important that applications call°dONLNd·/7;†(XU_GetPixBaseAddr°dONLNd0†<£)i °dONLNdÒ0£<¬)every°dONLNdˆ0¬<‹) time °dONLNd¸0‹<q)they are about to manipulate a °dONLNd/q;õ)ïGWorld°dONLNd!0õ<∂)* pixel°dONLNd(<7Hu(dU
  7209. map directly.°dONLNd6U*a.(}H•°dONLNd8U7aè)
  7210. When the source °dONLNdHTè`π)XPixMap°dONLNdNUπaE)* has a color table that uses °dONLNdkUEa∂)åindexes that refer to a°dONLNdÉa7mY(âUpalette.°dONLNdçy7Öp*
  7211. QuickDraw °dONLNdóypÖ∂)9Enow allows a color table to have indexes that point to entries in the°dONLNd›Ü7íÖ(ÆUCpalette associated with the destination window; when bit 14 in the °dONLNd ÖÖë∂(Æ£ctFlags°dONLNd(í7û(∫U,field is set, the value fields in the color °dONLNdTíû∂)π+table are treated as palette entries.  When°dONLNdÄü7´X(«Usuch a °dONLNdáûX™Ç)!PixMap°dONLNdçüÇ´‘)* is the source for °dONLNd†û‘™)R    _CopyBits°dONLNd©ü´ù)?, then GC QuickDraw has to °dONLNdƒüù´∂)ämake°dONLNd…´7∑è(”Ua number of calls °dONLNd€´è∑∂)X<to the Palette Manager as part of the setup before returning°dONLNd∑7√À(flU control and completing the call.°dONLNd:–7‹W*9This case is similar to that of a indexed pixel map when °dONLNds–W‹b(¯ua °dONLNduœb€®)
  7212. SearchProc°dONLNd–®‹∂)F is°dONLNdÉ‹7Ëa(UDinvolved; therefore, it only implies a partial loss of parallelism; °dONLNd«‹aË∂(it is good to keep°dONLNd⁄È7ı5(U6in mind that this case can only occur when the source °dONLNdË5Ù_)˛PixMap°dONLNdÈ_ıñ)*  is indexed.°dONLNd#%Ç(A6Further Reference: D4D˘°dONLNd6&*2.+
  7213. •°dONLNd8&<2ç)Inside Macintosh°dONLNdH&ç2?)Q!, Volumes V & VI, Color QuickDraw°dONLNdj2*>.(ZH•°dONLNdl2<>s)
  7214. d e v e l o p°dONLNdy2s>∑)7@, “Macintosh Display Card 8•24 GC:  The Naked Truth,” July 1990.°dONLNd∫>*J.(fH•°dONLNdº><Jh)<Technical Note #275, 32-Bit QuickDraw:  Version 1.2 Features°dONLNd˘J*V.(rH•°dONLNd˚J<V≥)FDeveloper Notes for the Macintosh Display Cards 4•8, 8•24 and 8•24 GC °dONLNd    AJ≥V⁄(r—(APDA,°dONLNd    HV<b|(~Z
  7215. M085TLL/A)°dONLNd    SnzÍ(ñ6*NuBus is a trademark of Texas Instruments. ◊4◊˘
  7216. *V2) of 2)˙+Deaccelerated _CopyBits & 8•24 GC QuickDrawˇ¬◊#ˇ ˇˇˇˇ#◊°d WORDS †å°d WORDR…†Ç 
  7217. /ZÅ#
  7218.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  7219. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  7220. .eRSeRS+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  7221. Ä({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  7222. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  7223.     l+&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  7224. BÄ(Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É°dWORD†ç
  7225. IR.°dONLNd{<é¥(®Z
  7226. Drawing Icons
  7227. °dONLNdç<úr*Imaging°dONLNdçxú˛(∏ñM.IM.DrawingIcons
  7228. °dONLNd(®<¥q(–Z Written by:°dONLNd4®Ñ¥Œ)HJim Friedlander°dONLNdD®æ¥˛(–‹ October 1985°dONLNdQ¡<ÕÚ(ÈZ$Using resources of type ICON allows °dONLNdu¡ÚÕU)∂drawing of icons in ,
  7229. Courier°dONLNdâ¿UÃx)csrcOr°dONLNdé¡xÕ˛)# mode.  Using resources of°dONLNd©Õ<ŸF(ıZ5type ICN# allows for more variety when drawing icons. X°dONLNdflÛ<ˇ>*&8There are two different kinds of resources that contain °dONLNdÛ>ˇØ(\icons: ICON and ICN#°dONLNd+ÚØ˛∂)q.°dONLNd,Û∂ˇ˛)
  7230.  An ICON is a°dONLNd:ˇ< È('Z[32 by 32 bit image of an icon and can be drawn using the following Toolbox Utilities calls:
  7231.     °dONLNdó`"Ò+$MyIconHndl:= GetIcon(iconID);°dONLNd∂!`,‚*
  7232. PlotIcon(destRect,iconID);
  7233. °dONLNd—7<Ci(_Z>While very convenient, this method only allows the drawing of °dONLNd7iC˛(_áicons in SrcOr mode (as in the°dONLNd.C<O≥(kZMiniFinder). The Finder °dONLNdFC≥O˛)wAuses resources of type ICN# to draw icons on the desktop. Because°dONLNdàO<[b(wZ>the Finder uses ICN#s, it can draw icons in a variety of ways.°dONLNd«g<sO*An °dONLNd gOs˛)PICN# resource is a list of 32 by 32 bit images that are grouped together. Common°dONLNds<˝(õZ'convention has been to group two 32 by °dONLNdBs˝˛)¡432 bit images together in each ICN#. The first image°dONLNdw<ã¢(ßZis the actual icon, the °dONLNdè¢ã˛)fEsecond image is the mask for the icon. To get a handle to an ICN#, we°dONLNd’ã<óÃ(≥Zwould use something like this:
  7234.     °dONLNdÙ£<ÆP*TYPE°dONLNd˙≠`∏›+$
  7235. iListHndl    = ^iListPtr;°dONLNd∑`¬Ï*
  7236. iListPtr     = ^iListStruct;°dONLNd3¡`Ã…*
  7237. iListStruct  = record°dONLNdKÀÑ÷B+$
  7238. &icon : packed array[0..31] of Longint;°dONLNdt’чB*
  7239. &mask : packed array[0..31] of Longint;°dONLNdúfl`Í∫(~End; {iListStruct}°dONLNdØÛ<˛K(ZVAR°dONLNd¥˝`‚+$
  7240. myILHndl      : iListHndl;°dONLNdœ˝w)ê        {handle to an ICN#}°dONLNdÏ`”(.~iBitMap       : BitMap;°dONLNdw)ê      {BitMap for the icon}°dONLNd!`”(8~mBitMap       : BitMap;°dONLNd9w)ê      {BitMap for the mask}°dONLNdV%`0_(L~3MyILHndl:= iListHndl(GetResource('ICN#',iconID));  °dONLNdç/`:*
  7241. #if MyILHndl = NIL then HandleError;°dONLNd¥9ÑD=+$
  7242. %{and exit or whatever is appropriate}
  7243. °dONLNd⁄O<[(wZ,Once we have a handle to the icons, we need °dONLNdO[˛)÷1to set up two bitMaps that we will be using later°dONLNd8\<hH(ÑZin °dONLNd;[HgÄ) CopyBits°dONLNdC\ÄhÉ)8:
  7244.     °dONLNdFt<P(õZ    °dONLNdKt`»)$HSetRect(icnRect,0,0,32,32);                { define the icon's 'bounds'}°dONLNdï~`â…*
  7245. With iBitMap do Begin°dONLNd´à<ìı(ØZ%         baseAddr:= @MyILHndl^^.icon;°dONLNd“í<ù™*
  7246.          rowbytes:= 4;°dONLNdÈíÃù)ê               °dONLNd˙í\ùù)ê
  7247.  { 4 * 8 =32}°dONLNdú<ßæ(√Z         bounds:= icnRect; ◊X◊
  7248. *)
  7249. Drawing Icons(Ï1) of 4ˇ°¿Ù%%DSIDICT:_cv
  7250. currentdict /bu known {bu}if
  7251. userdict /_cv known not{userdict /_cv 30 dict put}if
  7252. _cv begin
  7253. /bdf{bind def}bind def
  7254. currentscreen/cs exch def/ca exch def/cf exch def
  7255. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  7256. /ss{//cf //ca //cs setscreen}bdf
  7257. /stg{ss setgray}bdf
  7258. /strgb{ss setrgbcolor}bdf
  7259. /stcmyk{ss cvcmyk}bdf
  7260. /min1{dup 0 eq{pop 1}if}bdf
  7261. end
  7262. currentdict /bn known {bn}if
  7263. †ø t◊#ˇ ˇˇˇˇ#◊ 
  7264. IR,Times
  7265. .+6-Macintosh Technical Notes /4/˘,
  7266. Courier
  7267.     °dONLNd(h*     End; {with}°dONLNd'2"*
  7268.   °dONLNd'<2•)$With mBitMap do Begin°dONLNd*1<—(X6%         baseAddr:= @MyILHndl^^.mask;°dONLNdP;FÜ*
  7269.          rowbytes:= 4;°dONLNdgEPö*
  7270.          bounds:= icnRect;°dONLNdÇOZ"*
  7271.   °dONLNdÖO<Zs)$ End; {with}
  7272. °dONLNdëeqq(ç6LIcons can represent desktop objects that are either selected or not. Folder °dONLNd›eqq⁄(çèand volume icons can°dONLNdÚq}†(ô6Seither be open or not. The object (or the volume it is on) can either be online or °dONLNdEq†}⁄(ôæ offline. The°dONLNdR}âh(•6GFinder draws icons using all permutations of open, selected and online:†09†Ç†é
  7273. ¿MD·ò4fii    fin¿M¸·Õ˙÷ˇ˙÷ˇ˙ˆ¯ˆ˘˙ˆ¯ˆ˘˙ˆ¯ˆ˘˙ˆ¯ˆ˘˙ˆ¯ˆ˘˙ˆ¯ˆ˘#˙àĸÄx˛ˆ˚%˙à@¸ÄÑ˛¯˚*˙H‚¿O,˛ é,Ñ‚¿¯    ·≈IJ-˙I Hë2˛ë2Ñâ     ·≈Ä˚    &@˛-˙)'»Hë"˛ë"|Ñâ     &@˚    $@˛-˙) Hü"˛ë"ÑâÚ     $@˚    ‰@˛-˙ Hê"˛ë"Ñâ     ‰@˚    @˛-˙ Hë"˛ë"Ñâ     @˚    $@˛-˙‚ è"˛é"x‚     $@˚Ò·ƒ@˛#˙¸¸˚ÄÒ·ƒ@˚˚ ˙¸¸˚į˚˙ˆ¯¯˘˙ˆ¯ˆ˘˙ˆ¯ˆ˘˙ˆ¯ˆ˘˙ˆ¯ˆ˘˙ àįˆ˘0˙,à@0àÄ  0˙,H‚¿p„áÄà@  0˙,I àâë·«H‚¿p„á·p·‡0˙,)'«ààâë""I àâë"! 0˙,) Oà˘ë")'«ààâëÒ ! 0˙, HÅüÚ") Oà˘ë    Ò !Ú 0˙, Hàâëê" HÅ     ! 0˙,‚ áp‡«ë"" Hàâë    "! (˙ˆ ·¡é‚ áp‡«··‡˙ˆ¯ˆ˘˙ˆ¯ˆ˘˙ˆ¯ˆ˘˙ˆ¯ˆ˘˙ˆ¯ˆ˘˙ˆ¯ˆ˘œˇœˇ˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚˛ˇ˛¸¯ˆ˘˚˛Ä¸¯ˆ˘#˚˛Ä¸˛ˇˇ¿ˆ˘#˚˛èˇÒ¸˛ˇˇ¿ˆ˘'˚˛ê    ¸˛¿ˆ‡˝+˚˛ïU    ¸˛
  7274. ˇ˛¿˛D˙∏˝+˚˛ê    ¸˛
  7275.  
  7276. U^¿˙.Ï˝,˚˛ïP    ¸˛
  7277.  
  7278. ˇ˛¿D˙
  7279. ;ªª∏+˚˛ê    ¸˛
  7280. U˛¿˝¸˝Ó-˚˛ï    ¸˛    
  7281. ˇ˛¿˛D¸˛ª∫.¿  ˛ê    ¸˛
  7282. _˛¿˝¸˝Ó0 ˛˛ï    ¸˛    
  7283. ˇ˛¿˛D¸˛ª∫.%Ñb√Ä˛ê    ¸˛
  7284. _˛¿˝¸˝Ó0&D#$@˛ï@    ¸˛    
  7285. ˇ˛¿˛D¸˛ª∫.$D"$@˛ê    ¸˛
  7286. W˛¿˝¸˝Óò4iV    nV¸M8·0$D"'¿˛ê    ¸˛    
  7287. ˇ˛¿˛D¸˛ª∫.$D"$˛èˇÒ¸˛
  7288. ˇ˛¿˝¸˝Ó0$D"$@˛Ä¸˛    ¿˛D¸˛ª∫.ƒD"#IJĸ˛ˇˇ¿˝¸˝Ó-˚˛Ä¸˛    ˇˇ¿˛D¸˛ª∫+˚˛Ä¸˛ˇˇ¿˝¸˝Ó-˚˛ÄÒ¸˛    ˇˇ¿˛D¸˛ª∫+˚˛Ä¸˛˛¿˝¸˝Ó-˚˛Ä¸˛    ˇˇ¿˛D¸˛ª∫+˚˛Ä¸˛ˇˇ¿˝¸˝Ó-˚˛Ä¸˛    ˇˇ¿˛D¸˛ª∫+˚˛ˇ˛¸˛ˇˇ¿˝¸˝Ó'˚˛@¸¯˛D¸˛ª∫'˚˛@¸˛ˇˇÄ˝¸˘#˚˛@¸˛ˇˇÄˆ˘#˚˛ˇ˛¸˛ˇˇÄˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘œˇœˇ˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚˛ˇ˛¸¯ˆ˘˚˛¢"#¸¯ˆ˘#˚˛àà⸲ ªªÄˆ˘#˚˛ØˇÛ¸˛ÓÓ¿ˆ˘#˚˛òà⸲
  7289. Ĉ˘#˚˛∑w+¸˛ ÓÓ¿ˆ˘'˚˛òà⸲    Äˆ‡˝+˚˛∑r+¸˛ ÓÓ¿˛D˙∏˝+˚˛òà⸲
  7290.     ∫Ä˙.Ï˝,˚˛∑"+¸˛
  7291. ÓÓ¿D˙
  7292. ;ªª∏.¡Üa˛òà⸲    ∫Ä˝¸˝Ó0" ˛∑"+¸˛     ÓÓ¿˛D¸˛ª∫.'#˛òà⸲    ∫Ä˝¸˝Ó0"!"˛∑b+¸˛     ÓÓ¿˛D¸˛ª∫."!"˛òà⸲    ∫Ä˝¸˝Ó0"!>˛≤"+¸˛     ÓÓ¿˛D¸˛ª∫."! ˛èˇ˘¸˛    ª∫Ä˝¸˝Ó0"!"˛¢"#¸˛    ¿˛D¸˛ª∫.¬!˛àà⸲ ªªÄ˝¸˝Ó-˚˛¢"#¸˛    ÓÓ¿˛D¸˛ª∫+˚˛àà⸲ ªªÄ˝¸˝Ó-˚˛¢/Û¸˛    ÓÓ¿˛D¸˛ª∫+˚˛àà⸲ ∫Ä˝¸˝Ó-˚˛¢"#¸˛    ÓÓ¿˛D¸˛ª∫+˚˛àà⸲ ªªÄ˝¸˝Ó-˚˛¢"#¸˛    ÓÓ¿˛D¸˛ª∫+˚˛ˇ˛¸˛ ªªÄ˝¸˝Ó'˚˛b""¸¯˛D¸˛ª∫+˚˛Hà串ªªÄ˝¸˝Óò4Vib    Vnb8MD·-˚˛b""¸˛    ÓÓIJD¸˛ª∫'˚˛ˇ˛¸˛ªªÄ˝¸˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘˚ˆ¯ˆ˘œˇœˇÕ†è†É
  7293. IR°dONLNdö=I—*¿XDrawing icons as non-open is basically the same for online and offline volumes. We need °dONLNdÚ=—I⁄(eÔto°dONLNdıIU∂(q6Xpunch a hole in the desktop for the icon. This is analogous to punching a hole in dough °dONLNdMI∂U⁄(q‘with an°dONLNdUUaM(}6Birregular shaped cookie-cutter. We can then sprinkle jimmies* all °dONLNdóUMa⁄(}kover the cookie and they will°dONLNdµam≈(â6Zonly stick in the area that we punched out (the mask). We do this by copyBitsing the mask °dONLNda≈m⁄(â„onto°dONLNdmyö(ï6Qthe desktop (whatever pattern) to our destRect. For non-open, non-selected icons:†Ç†é
  7294. ò˝¿0ò\(Ñ`\-Ñ`ò˝¿0˘˘˘˘˘˘˘ˇ˛˛Ä˛Ä˛èˇÒ˛ê    ˛ïU    ˛ê    ˛ïP    ˛ê    ˛ï    ˛ê    ˛ï    ˛ê    ˛ï@    ˛ê    ˛ê    ˛èˇÒ˛Ä˛Ä˛Ä˛Ä˛ÄÒ˛Ä˛Ä˛Ä˛Ä˛ˇ˛˛@˛@˛@˛ˇ˛˛˘˘†è†É
  7295. IR°dONLNdg≠π*@5we use the SrcBic mode so that we punch a white hole:
  7296.     °dONLNdû≈<–+$*SetRect(destRect,left,top,left+32,top+32);°dONLNd œ<⁄|*
  7297. @CopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL);
  7298. °dONLNd ÂÒî(
  7299. 6Then we XOR in the icon:
  7300.     °dONLNd%˝* °dONLNd'˝<|)$@CopyBits(iBitMap,thePort^.portBits,icnRect,destRect,SrcXor,NIL);
  7301. °dONLNdh®(;6That’s all there is to drawing °dONLNdá®÷)ê:an icon as non-open, non-selected. To draw the icon as non°dONLNd¡÷⁄(;Ù-°dONLNd¬+^(G6open, selected:†Ç†é
  7302. JÚv;ò
  7303. —(˛x—.˛xJÚw<˜˜˜˜˜˜˜˜˜    ˛ˇˇ¯˛    ˛ˇˇ¯˛    ˛¿8˛    ˛øˇÿ˛    ˛™´ÿ˛    ˛øˇÿ˛    ˛™øÿ˛    ˛øˇÿ˛    ˛´ˇÿ˛    ˛øˇÿ˛    ˛´ˇÿ˛    ˛øˇÿ˛    ˛™ˇÿ˛    ˛øˇÿ˛    ˛øˇÿ˛    ˛¿8˛    ˛ˇˇ¯˛    ˛ˇˇ¯˛    ˛ˇˇ¯˛    ˛ˇˇ¯˛    ˛ˇ¿8˛    ˛ˇˇ¯˛    ˛ˇˇ¯˛    ˛ˇˇ¯˛    ˛ˇˇ¯˛˜˝ˇˇ˛˝ˇˇ˛˝ˇˇ˛˜˜˜˜˜˜˜†è†É
  7304. IR°dONLNd‹Wc *8Vwe will OR in the mask, causing a mask-shaped BLACK hole to be punched in the desktop:
  7305.     °dONLNd4o<zw+$?CopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcOr,NIL);
  7306. °dONLNduÖë (≠6$Then, as before, we XOR in the icon:
  7307.     °dONLNdõù<®|+$@CopyBits(iBitMap,thePort^.portBits,icnRect,destRect,SrcXOr,NIL); ◊4◊˘
  7308. (Ï62) of 4(Ïæ
  7309. Drawing IconsˇŒ◊#ˇ ˇˇˇˇ#◊ 
  7310. IR,Times
  7311. .+Z-Developer Support Center, Palatino(-„ October 1985 0X0
  7312. °dONLNd*<6)(RZ0To draw icons as non-opened for offline volumes:†Ç†é
  7313. U!~Tò[(Ñ`[,Ñ_U!~T˘˘˘˘˘˘˘˘ˇ˛˛¢"#˛ààâ˛ØˇÛ˛òàâ˛∑w+˛òàâ˛∑r+˛òàâ˛∑"+˛òàâ˛∑"+˛òàâ˛∑b+˛òàâ˛≤"+˛èˇ˘˛¢"#˛ààâ˛¢"#˛ààâ˛¢/Û˛ààâ˛¢"#˛ààâ˛¢"#˛ˇ˛˛b""˛Hàä˛b""˛ˇ˛˛˘˘†è†É
  7314. IR°dONLNd1_<k/*51we need to do a little more work. We need to XOR °dONLNdb_/k˛)Û+a ltGray pattern into the boundsRect of the°dONLNdék<w~(ìZBicon. We will then punch the hole, draw the icon and then XOR out °dONLNd–k~w˛(ìúthe ltgray pattern that does°dONLNdÌw<ÉÍ(üZ[not fall inside the mask. So, to draw the icon as offline, non-open, non-selected we would:,
  7315. Courier
  7316.     °dONLNdJè`öƒ+$GetPenState(OldPen);°dONLNd`èöΩ)ê){save the pen state so we can restore it}°dONLNdãô`§∞(¿~PenMode(patXor);°dONLNdú£<ÆF( Z  °dONLNdü£`Æ´)$PenPat(ltGray);°dONLNdØ≠<∏F(‘Z  °dONLNd≤≠`∏ƒ)$PaintRect(destRect);°dONLNd»≠∏§)ê${paint a ltGray background for icon}°dONLNdÌ¡<ÃF(ËZ  °dONLNd¡`û)$HCopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL); {punch}°dONLNd9À<÷A(ÚZ °dONLNd;À`÷»)$HPaintRect(destRect);{XOR out bits outside of the mask, leaving the mask}°dONLNdâ’Ç0+l
  7317. {filled with ltGray}°dONLNd´Í<ıA(Z °dONLNd–Ù<ˇ§*
  7318. HCopyBits(iBitMap,thePort^.portBits,icnRect,destRect,SrcOr,NIL);{ OR in }°dONLNdS˛\    ‘(%z{ the icon to the ltGray°dONLNdl<U(/Zmask}°dONLNdr<Æ*
  7319. JSetPenState(OldPen);                           {restore the old pen state}
  7320. °dONLNdΩ(<4*0To draw the icon as offline, non-open, selected:†Ç†é
  7321. SÇ]ò
  7322. À0˙xÀ4˙xSÇ]˜˜˜˜˜˜˜˜˜˜˜˜˜˛.ÓÓ˝˛;ªª˝˛(˝˛3ªª˝˛$Dj˝˛3ªª˝˛$FÍ˝˛3ªª˝˛$nÍ˝˛3ªª˝˛$nÍ˝˛3ªª˝˛$NÍ˝˛3ªª˝˛&ÓÍ˝˛8˝˛.ÓÓ˝˛;ªª˝˛.ÓÓ˝˛;ªª˝˛.Ë˝˛;ªª˝˛.ÓÓ˝˛;ªª˝˛.ÓÓ˝˜˛ÓÓ˝˛ª∫˝˛ÓÓ˝˜˜˜˜˜†è†É
  7323. IR°dONLNdÓc<o⁄*; we would use a similar approach:
  7324.     °dONLNd{<ÜP*    °dONLNd{`܃)$GetPenState(OldPen);°dONLNd*{ܬ)ê*{ save the pen state so we can restore it}°dONLNdVÖ`ê∞(¨~PenMode(patXor);°dONLNdhè`ö´*
  7325. PenPat(dkGray);°dONLNdyèö«)ê+{ the icon is selected, so we need dkGray }°dONLNd•ô<§F(¿Z  °dONLNd®ô`§ƒ)$PaintRect(destRect);°dONLNdæô§Æ)ê&{ paint a dkGray background for icon }°dONLNdÊ≠`∏(‘~ {punch a hole in the background}°dONLNd∑<¬F(fiZ  °dONLNd
  7326. ∑`¬†)$@CopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL);°dONLNdLÀ`÷ƒ*PaintRect(destRect);°dONLNdbÀ÷¬)ê*{XOR out bits outside of the mask, leaving°dONLNdí’‡Å*
  7327.  the mask filled with dkGray}°dONLNd±È`Ù(~!{BIC the icon to the dkGray mask}°dONLNd‘Û`˛†*
  7328. @CopyBits(iBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL);°dONLNd<F(.Z  °dONLNd`x)$8SetPenState(OldPen);         {restore the old pen state}
  7329. °dONLNdQ<*ä(FZCDrawing the opened icons requires one less step. We don’’t have to °dONLNdîä)¬(F®CopyBits°dONLNdú¬*ÿ)8 the °dONLNd°ÿ*˛)icon in,°dONLNd™*<6‚(RZ!we just use the mask. Online and °dONLNdÀ*‚6˛)¶6offline icons are drawn the same way. To draw icons as°dONLNd6<BÇ(^Zopen, selected:†Ç†é
  7330. aÉWòøN·éøT·åaÉW˘˘˘˘˘˘¿˝7p˝]ÿ˝    ˛wpˇ    ˛›‹ˇ    ˛wtˇ    ˛›‹ˇ    ˛wtˇ    ˛›‹ˇ    ˛wtˇ    ˛›‹ˇ    ˛wtˇ    ˛›‹ˇ    ˛wtˇ    ˛›‹ˇ    ˛wtˇ    ˛›‹ˇ    ˛wtˇ    ˛›‹ˇ    ˛wtˇ    ˛›‹ˇ    ˛wtˇ    ˛›‹ˇ    ˛wtˇ˘˘˘˘†è†É
  7331. IR°dONLNdd<pû*.we do the following:
  7332.     °dONLNd'|<áP*    °dONLNd,|`áƒ)$GetPenState(OldPen);°dONLNdB|áΩ)ê){save the pen state so we can restore it}°dONLNdlÜ<ëF(≠Z  °dONLNdoÜ`ë∞)$PenMode(patXor);°dONLNdÄê<õF(∑Z  °dONLNdÉê`õ´)$PenPat(dkGray);°dONLNdîêõ«)ê+{ the icon is selected, so we need dkGray }°dONLNd¿ö<•K(¡Z   °dONLNdƒö`•ƒ)$PaintRect(destRect);°dONLNd⁄ö•©)ê%{ paint a dkGray background for icon} ◊X◊
  7333. (ÏZ
  7334. Drawing Icons(Ï3) of 4ˇ–◊#ˇ ˇˇˇˇ#◊ 
  7335. IR,Times
  7336. .+6-Macintosh Technical Notes /4/˘,
  7337. Courier
  7338.     °dONLNd'<2‹+$! {punch a hole in the background}°dONLNd!1<"(X6  °dONLNd$1<<|)$@CopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL);°dONLNdeEP"(l6  °dONLNdkE<P™)$PaintRect(destRect);  °dONLNdÇEÃPû)ê*{XOR out bits outside of the mask, leaving°dONLNd≥OÃZX*
  7339. the mask filled with dkGray}°dONLNd–Yd"(Ä6  °dONLNd”Y<d†)$SetPenState(OldPen);°dONLNdÈYÃdS)ê{restore the old pen state}
  7340. °dONLNdo{»(ó6$To draw icons as open, non-selected:†Ç†é
  7341. ö˜∫6ò
  7342. fpÜ∏fsÜ≤ö˜∫6˜˜˜˜˜˜ ˚Ä˚" ˚˝à˝    ˛" ˝˝à˝    ˛" ˝˝à˝    ˛" ˝˝à˝    ˛" ˝˝à˝    ˛" ˝˝à˝    ˛" ˝˝à˝    ˛" ˝˝à˝    ˛" ˝˝à˝    ˛" ˝˝à˝    ˛" ˝˝à˝˜˜†è†É
  7343. IR°dONLNd*ß≥h*8Ewe just need to change one line from above. Instead of XORing with a °dONLNdoßh≥⁄(œÜdkGray pattern, we use°dONLNdÜ≥ød(€6a ltGray pattern:
  7344.     °dONLNdòÀ÷"*  °dONLNdõÀ<÷á)$PenPat(ltGray);°dONLNd¨ÀÃ÷ô)ê){icon is non-selected, so we need ltGray}
  7345. °dONLNd÷·Ì“(    6"These techniques will work on any °dONLNd¯·“Ì⁄)∫0background, window-white or desktop-gray and all°dONLNd)Ì˘™(6patterns in between. Have fun.°dONLNdH!*$* °dONLNdJ!I)    jimmies °dONLNdRI≥)(: little bits of chocolate°dONLNdmAMÇ(i6Further Reference: l4l˘°dONLNdÄN*Z.+
  7346. •°dONLNdÇN<Zr)    QuickDraw°dONLNdåZ*f.(ÇH•°dONLNdéZ<få)Toolbox Utilities ◊4◊˘
  7347. (Ï64) of 4(Ïæ
  7348. Drawing Iconsˇö◊#ˇ ˇˇˇˇ#◊°d WORDS †å°d WORDR…†Ç 
  7349. /ZÅ#
  7350.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  7351. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  7352. .eRSeRS+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  7353. Ä({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  7354. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  7355.     l+&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  7356. BÄ(Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É°dWORD†ç
  7357. IR.°dONLNd{<éO(®ZDrawing Icons the System 7 Way
  7358. °dONLNdç<úr*Imaging°dONLNd'ç~ú˛(∏úM.IM.IconDrawing
  7359. °dONLNd8®<¥t(–Z Revised by:°dONLNdD®Ñ¥*)HDon Moccia and C.K. Haun <TR>°dONLNdb®æ¥˛(–‹ October 1992°dONLNdo¥<¿q(‹Z Written by:°dONLNd{¥Ñ¿)HJim Mensch and David Collins°dONLNdò¥æ¿˛(‹‹ October 1991°dONLNd•Ã<ÿO(ÙZ:This Technical Note describes how to utilize the built-in °dONLNdflÃOÿ˛(Ùm"System 7 icon drawing utility. Use°dONLNdÿ<‰ò(ZJthis information to better conform to the System 7 visual human interface.°dONLNdM<¸–*Changes since May 1992:°dONLNdd–¸‘)î6 In this Note, we replaced the C and Pascal interface °dONLNdö‘¸˛(Ú    files and°dONLNd§¸<Ω($ZOcorrected the related text. So much text was tweaked that change bars are used °dONLNdÛ¸Ω˛($€ only on code°dONLNd<f(0Zchanges. ?X?
  7360. °dONLNd
  7361. 9<Hè*4 Introduction
  7362. °dONLNdT<`*[With the introduction of System 7 for the Macintosh, Apple has defined a new look and feel °dONLNdrT`˛(|for°dONLNdv`<l`(àZ<many screen elements that better utilize color. Among those °dONLNd≤``l˛(à~ redefined elements are the icons°dONLNd”l<xÈ(îZUdrawn by the Finder and other system components. Until now, Apple has not documented °dONLNd(lÈx˛(îhow°dONLNd,x<Ñ/(†Z2to draw icons the way the Finder does in System 7.°dONLNd_ê<úö*MThis Technical Note discusses the icon toolkit calls that the Finder uses to °dONLNd¨êöú˛(∏∏draw and manipulate°dONLNd¿ù<©·(≈Z$the screen icons. Two of the calls, ,
  7363. Courier°dONLNd‰ú·®')•
  7364. PlotIconID°dONLNdÓù'©>)F and °dONLNdÛú>®ß)PlotCIconHandle°dONLNdùß©Æ)i, °dONLNdùÆ©˛)are the ones you°dONLNd©<µî(—Zwill probably use °dONLNd'©îµ˛)XHthe most since they simply deal with drawing single icons to the screen.°dONLNdpµ<¡∫(›ZSome parts of the toolbox°dONLNdâµ∫¡ø)~ °dONLNdäµø¡t)&require that an icon family handle be °dONLNd∞µt¡˛)µpassed to them to allow the°dONLNdá<Õë(ÈZdrawing of color °dONLNd›¡ëÕ˛)UJicons. The icon toolkit provides calls that allow you to create, draw, and°dONLNd(Õ<Ÿµ(ıZmanipulate these handles.
  7365. °dONLNdBÒ<|*'The New °dONLNdJÚ|†)@'ic'°dONLNdNÒ†
  7366. )$ Type Resources
  7367. °dONLNd^ <Ç(5Z
  7368. PlotIconID°dONLNdh
  7369. Çô)F and °dONLNdm ô)PlotCIconHandle°dONLNd|
  7370. ~)i allow the use of standard °dONLNdó ~®)|CIcons°dONLNdù
  7371. ®∏)* as °dONLNd°
  7372. ∏˛)
  7373. documented in°dONLNdØ<&ê(BZInside Macintosh °dONLNd¿ê&‹)TVolume V. The °dONLNdŒ‹%")L
  7374. PlotIconID°dONLNdÿ"&8)F call °dONLNdfi8&˛))also permits the use of a new set of icon°dONLNd&<2¥(NZresources documented in °dONLNd &¥2)xInside Macintosh °dONLNd1&2C)T Volume VI, °dONLNd<&C2˛);'Chapter 9. This new set is a collection°dONLNdd2<>‡(ZZ[of different icons, representing a single Finder object, into a family. Each member of the °dONLNdø2‡>˛(Z˛family°dONLNdΔ?<K·(gZ has the same resource ID as the °dONLNdÊ>·J )•'ICN#'°dONLNdÏ? K*)*, and °dONLNdÚ?*K˛)+a resource type indicating the icon data it°dONLNdK<Wª(sZPcontains. Currently Apple has defined three sizes of icons and three bit depths °dONLNdnKªW˛(sŸfor each size.°dONLNd}W<cb(Z@The sizes are large (32 by 32 pixels), small (16 by 16 pixels), °dONLNdΩWbc˛(Äand mini (12 by 12 pixels). The°dONLNd›c<ow(ãZEbit depths are 1, 4, and 8. The actual resource types are defined as:
  7375.     °dONLNd#{<ÜÕ*Large1BitMask    =    'ICN#';°dONLNdAÖ<êÕ*
  7376. Large4BitData    =    'icl4';°dONLNd_è<öÕ*
  7377. Large8BitData    =    'icl8';°dONLNd}ô<§Õ*
  7378. Small1BitMask    =    'ics#';°dONLNdõ£<ÆÕ*
  7379. Small4BitData    =    'ics4';°dONLNdπ≠<∏Õ*
  7380. Small8BitData    =    'ics8'; ‚X‚
  7381. *#Drawing Icons the System 7 Way(˜ˇ1, Palatino
  7382. ) 
  7383. )of 12ˇ°¿Ù%%DSIDICT:_cv
  7384. currentdict /bu known {bu}if
  7385. userdict /_cv known not{userdict /_cv 30 dict put}if
  7386. _cv begin
  7387. /bdf{bind def}bind def
  7388. currentscreen/cs exch def/ca exch def/cf exch def
  7389. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  7390. /ss{//cf //ca //cs setscreen}bdf
  7391. /stg{ss setgray}bdf
  7392. /strgb{ss setrgbcolor}bdf
  7393. /stcmyk{ss cvcmyk}bdf
  7394. /min1{dup 0 eq{pop 1}if}bdf
  7395. end
  7396. currentdict /bn known {bn}if
  7397. †ø™◊#ˇ ˇˇˇˇ#◊ 
  7398. IR,Times
  7399. .+6-Macintosh Technical Notes /4/˘,
  7400. Courier
  7401.     °dONLNd(©*Mini1BitMask     =    'icm#';°dONLNd'2©*
  7402. Mini4BitData     =    'icm4';°dONLNd<1<©*
  7403. Mini8BitData     =    'icm8';
  7404. °dONLNdZGS£*RThe 1-bit-per-pixel member of each size also contains the mask data for all icons °dONLNd¨G£S⁄(o¡ of that size°dONLNdπS_]({6E(yes, this means that all your icons of a certain size must have the °dONLNd˛S]_÷({{same mask). A 1-bit-per°dONLNdS÷_⁄)y-°dONLNd`l](à6
  7405. pixel member °dONLNd#`]l)E#must exist for each icon size that °dONLNdF_kM)™
  7406. PlotIconID°dONLNdP`Ml⁄)F uses. The icon size used is°dONLNdmlx∂(î6]determined by the size of the destination rectangle. If the destination rectangle is greater °dONLNd l∂x⁄(î‘than 16°dONLNd“xÑ(†6:pixels on a side then the large icon will be used. If the °dONLNd xÑ⁄(†7(rectangle is 13–16 pixels on both sides,°dONLNd5Ñê (¨6)the small icon will be used. If it is 12 °dONLNd^Ñ ê⁄)≤9or less on each side, the mini-icon will be used. The bit°dONLNdòêúÃ(∏6%depth is determined by the device of °dONLNdΩêÃú⁄)¥6the grafPort you plot into at drawing time. Be sure to°dONLNdÙú®&(ƒ69create a color grafPort when you want to use color icons.
  7407. °dONLNd.¿œ*'$Icon Families (or Suites and Caches °dONLNdR¿œ⁄(Î;As the Tool Set Refers to°dONLNdlœfiC(˙6Them)
  7408. °dONLNdr͈@*An icon °dONLNdzÍ@ˆ⁄)(Vfamily is simply a collection of icon handles that contain up to one image of each bit°dONLNd—ˆq(6Jdepth and size for a given icon. The family can be fully populated (every °dONLNdˆq⁄(èpossible size or depth°dONLNd2e(*6available), or it °dONLNdDe⁄)MJcan have only those icons that exist or are needed. By using families, you°dONLNdèT(66@remove the need to determine which size or depth of icon to use °dONLNdœT⁄(6rwhen drawing into a given°dONLNdÈ&Δ(B6Vrectangle. Several system routines, the Notification Manager for example, can take an °dONLNd?Δ&⁄(B‰icon°dONLNdD&2>(N6;family handle when an icon is requested. This permits them °dONLNd&>2⁄(N\ to use the proper color icons if°dONLNd†2>≠(Z6Xavailable. In the case of a sparsely populated icon family, when the proper icon is not °dONLNd¯2≠>⁄(ZÀ
  7409. available,°dONLNd>JD(f6Dthe icon toolkit will pick a substitute to produce the best results.°dONLNdHWcÍ**An icon cache is a family that also has a °dONLNdrVÍb)“ProcPtr°dONLNdyWc )1 °dONLNdzW cB)and a °dONLNdÄVBbl)"refCon°dONLNdÜWlc⁄)*. The main difference°dONLNdúcoJ(ã6
  7410. between a °dONLNd¶cJo⁄)2Tcache and a family is that the elements of the cache’s array are sparsely populated.°dONLNd˚o{L(ó6BWhen using an icon cache, the system either will use the entry in °dONLNd=oL{⁄(ójthe icon family portion of the°dONLNd\|à˙(§63cache or, if the desired element is empty, it will °dONLNdè|˙à©)‚%call the procedure pointed to by the °dONLNd¥{©á⁄)ØProcPtr°dONLNdºàîw(∞6Land request the data for the icon. The procedure should have this interface:
  7411.     °dONLNd    †´—*%FUNCTION IconGetter(theType: ResType;°dONLNd/™µ˛*
  7412. .                    yourDataPtr: Ptr): Handle;
  7413. °dONLNd^¿Ã*7This function should return either the icon data to be °dONLNdï¿Ã⁄)˘*drawn or NIL to signify that this entry in°dONLNd¿Ãÿ@(Ù6    the icon °dONLNd…Ã@ÿ⁄)(Ucache does not exist. Icon caches can be used with all icon family calls. A few extra°dONLNd    ÿ‰ˇ(63calls are also available to manipulate icon caches.
  7414. °dONLNd    S¸ Ê*'Drawing Modes or Transforms
  7415. °dONLNd    o#`*In addition to °dONLNd    ~`#⁄)HHvarious sizes and bit depths, icons can be drawn with different modes or°dONLNd    «#/å(K6transforms. Transforms °dONLNd    fi#å/⁄)tFare analogous to certain Finder states for the icons. For example, the°dONLNd
  7416. %0<›(X6(transform that you would use to show an °dONLNd
  7417. M0›<ó)≈(icon of a disk that has been ejected is °dONLNd
  7418. u/ó;÷)∫    ttOffline°dONLNd
  7419. ~0÷<⁄)?.°dONLNd
  7420. Ä<H÷(d6+Here is a list of the available transforms:
  7421.     °dONLNd
  7422. ¨T_Æ*ttNone                =    $0;°dONLNd
  7423. À^iÆ*
  7424. ttDisabled            =    $1;°dONLNd
  7425. ÍhsÆ*
  7426. ttOffline             =    $2;°dONLNd     r}Æ*
  7427. ttOpen                =    $3;°dONLNd (|áΩ*
  7428. !ttSelected            =    $4000;°dONLNd JÜë!*
  7429. 5ttSelectedDisabled    =    (ttSelected + ttDisabled);°dONLNd Äêõ*
  7430. 4ttSelectedOffline     =    (ttSelected + ttOffline);°dONLNd µö•
  7431. *
  7432. 1ttSelectedOpen        =    (ttSelected + ttOpen); ‚4‚˘
  7433. *62) of 12(˜qDrawing Icons the System 7 Wayˇî◊#ˇ ˇˇˇˇ#◊ 
  7434. IR,Times
  7435. .+Z-Developer Support Center(-Ê October 1992 /X/
  7436. °dONLNd<)¶(EZThe actual appearance °dONLNd¶)˛)jDof the icon drawn by each transform type may vary with future system°dONLNd[)<5Ë(QZ[software, so you should always use the transform that best fits the state it represents in °dONLNd∂)Ë5˛(Qyour°dONLNdª5<Aå(]ZHapplication. This way you will be consistent with future changes to the °dONLNd5åA˛(]™look and feel of regular°dONLNdB<NØ(jZsystem icons. Note the ,
  7437. Courier°dONLNd3AØMı)s
  7438. ttSelected°dONLNd=BıN{)F transform can be added to °dONLNdXB{N˛)Üany of the other transform°dONLNdsN<ZY(vZtypes.°dONLNdzf<r´*NThere are also transforms that use the Finder label colors to color the icon. °dONLNd»f´r˛(é…To determine the°dONLNdŸs< (õZ3proper label for a file’s icon, you can check bits °dONLNd s V)‰ 1–3 of the °dONLNdrV~á)6fdFlags°dONLNdsá˛)1 field in the file’s Finder°dONLNd:<ã(ßZinfo. (See the °dONLNdIã)CFinder Interface chapter in °dONLNdeãT)ÉInside Macintosh°dONLNduTã˛)R! Volume VI for more information).°dONLNdóå<òê(¥ZFThese bits contain a number from 0 to 7. Simply add the corresponding °dONLNd›ãêó»(¥ÆttLabel °dONLNdÂå»ò)8    value to °dONLNdÓåò˛)(the°dONLNdÚò<§É(¿ZItransform that you give the call. The label values are defined like this:
  7439.     °dONLNd<∞<ªØ*ttLabel1    =    $0100;°dONLNdT∫<≈Ø*
  7440. ttLabel2    =    $0200;°dONLNdlƒ<œØ*
  7441. ttLabel3    =    $0300;°dONLNdÑŒ<ŸØ*
  7442. ttLabel4    =    $0400;°dONLNdúÿ<„Ø*
  7443. ttLabel5    =    $0500;°dONLNd¥‚<ÌØ*
  7444. ttLabel6    =    $0600;°dONLNdÃÏ<˜Ø*
  7445. ttLabel7    =    $0700;
  7446. °dONLNd‰<Å*&    Alignment
  7447. °dONLNdÓ)<5Ÿ*TMost icons do not fully fill their rectangle, and it is sometimes necessary to draw °dONLNdB)Ÿ5˛(Q˜an icon°dONLNdJ5<Aº(]ZUrelative to other data (like menu text). In these instances it is nice to be able to °dONLNdü5ºA˛(]⁄
  7448. have the icon°dONLNd≠A<Mg(iZmove in °dONLNdµAgM˛)+Xits rectangle so that it will be at a predictable location in the destination rectangle.°dONLNdM<Y´(uZCWhen drawing an icon you can pass one of these standard alignments °dONLNdQM´Y˛(u…in the alignment°dONLNdbY<e§(ÅZKparameter or you can add a vertical alignment to a horizontal alignment to °dONLNd≠Y§e˛(Ŭcreate a composite°dONLNd¿e<qä(çZalignment value.
  7449.     °dONLNd—}<à“*atNone                =    $0;°dONLNdá<í“*
  7450. atVerticalCenter      =    $1;°dONLNdë<ú“*
  7451. atTop                 =    $2;°dONLNd.õ<¶“*
  7452. atBottom              =    $3;°dONLNdM•<∞“*
  7453. atHorizontalCenter    =    $4;°dONLNdlØ<∫ã*
  7454. CatAbsoluteCenter      =    (atVerticalCenter + atHorizontalCenter);°dONLNd∞π<ƒT*
  7455. 8atCenterTop           =    (atTop + atHorizontalCenter);°dONLNdÈ√<Œc*
  7456. ;atCenterBottom        =    (atBottom + atHorizontalCenter);°dONLNd%Õ<ÿ“*
  7457. atLeft                =    $8;°dONLNdD◊<‚O*
  7458. 7atCenterLeft          =    (atVerticalCenter + atLeft);°dONLNd|·<Ï*
  7459. ,atTopLeft             =    (atTop + atLeft);°dONLNd©Î<ˆ'*
  7460. /atBottomLeft          =    (atBottom + atLeft);°dONLNdŸı<“*
  7461. atRight               =    $C;°dONLNd¯ˇ<
  7462. T*
  7463. 8atCenterRight         =    (atVerticalCenter + atRight);°dONLNd1    <*
  7464. -atTopRight            =    (atTop + atRight);°dONLNd_<,*
  7465. 0atBottomRight         =    (atBottom + atRight);
  7466. °dONLNdê5<Dµ*&5And Now (Drum Roll Please) the Calls and What to Pass
  7467. °dONLNdΔP<\n*<Now that we have defined every major data type we can think °dONLNd    Pn\˛(xåof, here are the actual toolkit°dONLNd    "]<i(ÖZ0calls themselves. One word of caution: only the °dONLNd    R\hz)„
  7468. ForEachIconDo°dONLNd    _]zi∏)[ call protects °dONLNd    n]∏i˛)>the handle that°dONLNd    ~i<uQ(ëZ:is passed to it, so make your icon resources nonpurgeable.°dONLNd    πÅ<ç°*Icon Family Calls
  7469.     °dONLNd    Àô<§O*7FUNCTION NewIconSuite(VAR theIconSuite: Handle): OSErr; ‚X‚
  7470. *7Drawing Icons the System 7 Way(˜ˇ3) of 12ˇx◊#ˇ ˇˇˇˇ#◊ 
  7471. IR,Times
  7472. .+6-Macintosh Technical Notes /4/˘,
  7473. Courier
  7474. °dONLNd)l* NewIconSuite°dONLNd l*£)TA returns an empty icon family handle with all members set to NIL.
  7475.     °dONLNdN6AÙ(]6,FUNCTION AddIconToSuite(theIconData: Handle;°dONLNd{@KÂ*
  7476. )                        theSuite: Handle;°dONLNd•JU
  7477. *
  7478. 1                        theType: ResType): OSErr;
  7479. °dONLNd◊am¥*This call will add the data in °dONLNdˆ`¥l)ú theIconData°dONLNdamq)M into the suite at the °dONLNdaqm⁄)plocation reserved for°dONLNd.myI(ñ6theType°dONLNd5nIzí)1 of icon data. °dONLNdDmíyÙ)IAddIconToSuite°dONLNdRnÙz`)b will replace any old °dONLNdhn`z⁄)ldata in that slot without°dONLNdÇ{áfl(£6)disposing of it, so you may want to call °dONLNd´zflÜO)«GetIconFromSuite°dONLNdª{Oá⁄)p to obtain the old handle (if°dONLNdŸàîB(∞6Bany) to dispose of it. This call will be used most often with the °dONLNdáBìñ(∞` NewIconSuite°dONLNd'àñî⁄)T call to fill the°dONLNd9(º6 empty family after it’s created.
  7480.     °dONLNdZ¨∑*2FUNCTION GetIconFromSuite(VAR theIconData: Handle;°dONLNdç∂¡Ô*
  7481. +                          theSuite: Handle;°dONLNdπ¿À*
  7482. 3                          theType: ResType): OSErr;
  7483. °dONLNdÌ◊„V*FThis call will return a handle to the pixel data of the family member °dONLNd3◊V„d(ˇtof °dONLNd6÷d‚ú)theSuite°dONLNd>◊ú„⁄)8
  7484.  specified by°dONLNdL„ÔI( 6theType°dONLNdS‰Iú)1. If you intend to °dONLNdf‰úV)S(dispose of this handle, be sure to call °dONLNdé„VÔ∏)∫AddIconToSuite°dONLNdú‰∏⁄)b with a°dONLNd§¸‘(6(NIL handle to zero out the family entry.
  7485.     °dONLNdÕ‡*(FUNCTION ForEachIconDo(theSuite: Handle;°dONLNdˆ*
  7486. 3                       selector: IconSelectorValue;°dONLNd*'Í*
  7487. *                       action: IconAction;°dONLNdU&1*
  7488. 0                       yourDataPtr: Ptr): OSErr;
  7489. °dONLNdÜ=Iö*This routine will call your °dONLNd¢<öH‡)Ç
  7490. IconAction°dONLNd¨=‡I)F  procedure °dONLNd∑=I⁄)7'(see below) for each icon in the family°dONLNdflJVV(r6
  7491. specified by °dONLNdÏIVUé)>selector°dONLNdÙJéVí)8 °dONLNdıJíV®)and °dONLNd˘I®U‡)theSuite°dONLNdJ‡V)8. The °dONLNdIU8) selector°dONLNdJ8V⁄)8# parameter is a bit-level flag that°dONLNd3Vb≥(~6specifies which family members °dONLNdRV≥b⁄)õ=to operate on; they can be added together to create composite°dONLNdêbn§(ä6Uselectors that work on several different family members. The values for selector are:
  7492.     °dONLNdÊzÖ¬*"svLarge1Bit        =    $00000001;°dONLNd    Ñè¬*
  7493. "svLarge4Bit        =    $00000002;°dONLNd,éô¬*
  7494. "svLarge8Bit        =    $00000004;°dONLNdOò£¬*
  7495. "svSmall1Bit        =    $00000100;°dONLNdr¢≠¬*
  7496. "svSmall4Bit        =    $00000200;°dONLNdï¨∑¬*
  7497. "svSmall8Bit        =    $00000400;°dONLNd∏∂¡¬*
  7498. "svMini1Bit         =    $00010000;°dONLNd€¿À¬*
  7499. "svMini4Bit         =    $00020000;°dONLNd˛ ’¬*
  7500. "svMini8Bit         =    $00040000;°dONLNd!‘fl¬*
  7501. "svAllLargeData     =    $000000FF;°dONLNdDfiȬ*
  7502. "svAllSmallData     =    $0000FF00;°dONLNdgËÛ¬*
  7503. "svAllMiniData      =    $00FF0000;°dONLNdäÚ˝]*
  7504. AsvAll1BitData      =    (svLarge1Bit + svSmall1Bit + svMini1Bit);°dONLNdø]*
  7505. AsvAll4BitData      =    (svLarge4Bit + svSmall4Bit + svMini4Bit);°dONLNd]*
  7506. AsvAll8BitData      =    (svLarge8Bit + svSmall8Bit + svMini8Bit);°dONLNdP¬*
  7507. "svAllAvailableD    =    $FFFFFFFF;
  7508. °dONLNds&2◊**The action procedure that gets called for °dONLNdù&◊2⁄)ø7each icon type selected for the family is a Pascal type°dONLNd’2>«(Z6&function with the following interface:
  7509.     °dONLNd¸JU—*%FUNCTION IconAction(theType: ResType;°dONLNd    "T_‡*
  7510. (                    VAR theIcon: Handle;°dONLNd    K^i˘*
  7511. -                    yourDataPtr: Ptr): OSErr;
  7512. °dONLNd    yuÅb*The parameter °dONLNd    átbÄì)JtheIcon°dONLNd    éuìÅ4)1  is passed by reference here so °dONLNd    Æu4Å⁄)° that your routine can modify the°dONLNd    œÇéæ(™6$contents of the suite directly. The °dONLNd    ÛÅæç)¶ yourDataPtr °dONLNd    ˇÇé⁄)U¶meter is the value passed when you°dONLNd
  7513. &èõ8(∑6called °dONLNd
  7514. -é8öì) 
  7515. ForEachIconDo°dONLNd
  7516. :èìõT)[&. It allows you to easily communicate °dONLNd
  7517. `èTõ⁄)¡with your application. The°dONLNd
  7518. {ú®≥(ƒ6action procedure returns an °dONLNd
  7519. óõ≥ß÷)õOSErr°dONLNd
  7520. úú÷®0)#. If any value °dONLNd
  7521. ´ú0®p)Z other than °dONLNd
  7522. ∂õpßì)@noErr°dONLNd
  7523. ªúì®⁄)#
  7524.  is returned,°dONLNd
  7525. …®¥s(—6
  7526. ForEachIconDo°dONLNd
  7527. ÷©sµ≈)[F will stop processing immediately and return the error passed. (Note: °dONLNd ©≈µ⁄(—„This ‚4‚˘
  7528. (˜64) of 12(˜qDrawing Icons the System 7 Wayˇ◊#ˇ ˇˇˇˇ#◊ 
  7529. IR,Times
  7530. .+Z-Developer Support Center(-Ê October 1992 /X/
  7531. °dONLNd<)·(EZ$implies that the icons selected may °dONLNd$·)˛)•;only be partially operated on. There is no guaranteed order°dONLNd`)<5Â(QZ$in which the icons get operated on.),
  7532. Courier
  7533.     °dONLNdÖA<L'*/FUNCTION GetIconSuite(VAR theIconSuite: Handle;°dONLNdµK<V*
  7534. (                      theResID: INTEGER;°dONLNdfiU<`^*
  7535. :                      selector: IconSelectorValue): OSErr;
  7536. °dONLNdk<wê* GetIconSuite°dONLNd%lêx¸)T will create a new icon °dONLNd=l¸x˛)l7family and fill it from the current resource chain with°dONLNduy<Öµ(°Zthe icons of resource ID °dONLNdéxµÑÌ)ytheResID°dONLNdñyÌÖa)8 and types indicated by °dONLNdÆxaÑô)tselector°dONLNd∂yôÖÏ)8. This is the call °dONLNd…yÏÖ˛)Syou°dONLNdÕÜ<íá(ÆZHwill probably use most often to create an icon family. Note that if you °dONLNdÖáë˛(Æ•SetResLoad(False)°dONLNd'í<ûØ(∫ZQbefore making this call, the suite will be filled with unloaded resource handles.
  7537.     °dONLNdy™<µı*%FUNCTION PlotIconSuite(theRect: Rect;°dONLNdü¥<ø,*
  7538. 0                       align: IconAlignmentType;°dONLNd–æ<…@*
  7539. 4                       transform: IconTransformType;°dONLNd»<”@*
  7540. 4                       theIconSuite: Handle): OSErr;
  7541. °dONLNd:fi<Í*]This call renders the proper icon image from the passed icon family based on the bit depth of°dONLNdôÍ<ˆœ* the display you are using and °dONLNd∑Íœˆ˛)ì<the rectangle that you have passed. The parameters align and°dONLNdÙˆ<(ZYtransform are applied to the icon selected for drawing and then the icon is plotted into °dONLNdMˆ˛(the°dONLNdQ<í(+Zcurrent grafPort. °dONLNdcíÌ)V
  7542. PlotIconSuite°dONLNdpÌj)[ chooses the appropriate °dONLNdâj˛)}icon based primarily on size.°dONLNdß<Y(7ZOnce °dONLNd¨Y˛)Tthe proper icon size is determined (based on the destination rectangle), the present°dONLNd<'ì(CZKmember of that size with the deepest bit depth that the current device can °dONLNdLì'˛(C±use is selected. A size°dONLNdd(<4z(PZ category is °dONLNdp(z4–)>>considered present if the black-and-white member (with mask), °dONLNdÆ'–3˙(PÓ'ICN#'°dONLNd¥(˙4˛)*,°dONLNd∂4<@f(]Z'ics#'°dONLNdº5fAÑ)*, or °dONLNd¡4Ñ@Æ)'icm#'°dONLNd«5ÆA )*, is °dONLNdÃ5 A˘)    present. °dONLNd’4˘@T)/
  7543. PlotIconSuite°dONLNd‚5TA˛)[ can be used for both picture°dONLNdA<M∫(iZaccumulation and printing.
  7544.     °dONLNdY<d'*/FUNCTION DisposeIconSuite(theIconSuite: Handle;°dONLNdKc<nO*
  7545. 7                          disposeData: BOOLEAN): OSErr;
  7546. °dONLNdÉz<Üì*This call disposes °dONLNdñzìÜh)W/the icon family handle itself. In addition, if °dONLNd≈yhÖµ)’ disposeData°dONLNd–zµÜ˛)M is true, any of°dONLNd·Ü<í∂(ÆZRthe icon data handles that do not belong to a resource fork will also be disposed.
  7547.     °dONLNd4û<©ã*CFUNCTION SetSuiteLabel(theSuite: Handle; theLabel: INTEGER): OSErr;
  7548. °dONLNdx¥<¿ª*TThis call allows you to specify a label to draw an icon of this suite when no label °dONLNdÃ¥ª¿˛(‹Ÿis specified in°dONLNd‹¿<Ãó(ÈZ
  7549. PlotIconSuite°dONLNdÈ¡óÕ∑)[=. This is used primarily to ensure that a family passed to a °dONLNd&¡∑Õ˛(È’system routine°dONLNd5Õ<Ÿs(ıZ gets drawn °dONLNd@ÕsŸ˛)7Swith the proper label. The default label can be overridden by specifying a label in°dONLNdîŸ<Âó(Z
  7550. PlotIconSuite°dONLNd°⁄óÊõ)[.
  7551.     °dONLNd£Ú<˝6(Z2FUNCTION GetSuiteLabel(theSuite: Handle): INTEGER;
  7552. °dONLNd÷<ó*
  7553. GetSuiteLabel°dONLNd„    óE)[' returns the label previously set with °dONLNd    
  7554. E†)Æ
  7555. SetSuiteLabel°dONLNd        †§)[.°dONLNd    !<-ú(IZIcon Cache Calls°dONLNd    *9<Eô*NIn addition to the icon family calls, icon caches have these additional calls:
  7556.     °dONLNd    zQ<\*-FUNCTION MakeIconCache(VAR theHandle: Handle;°dONLNd    ®[<f*
  7557. ,                       makeIcon: IconGetter;°dONLNd    ’e<pE*
  7558. 5                       yourDataPtr: UNIV Ptr): OSErr;
  7559. °dONLNd
  7560. |<à*1This call creates an empty icon cache similar to °dONLNd
  7561. <{áo)fl NewIconSuite°dONLNd
  7562. H|oàv)T, °dONLNd
  7563. J|và˛)and associates the additional°dONLNd
  7564. hà<î<(∞Z6icon loading procedure and data value with the family.
  7565.     °dONLNd
  7566. ü†<´ı*%FUNCTION LoadIconCache(theRect: Rect;°dONLNd
  7567. ≈™<µ,*
  7568. 0                       align: IconAlignmentType; ‚X‚
  7569. *&Drawing Icons the System 7 Way(˜ˇ5) of 12ˇF◊#ˇ ˇˇˇˇ#◊ 
  7570. IR,Times
  7571. .+6-Macintosh Technical Notes /4/˘,
  7572. Courier
  7573.     °dONLNd(*4                       transform: IconTransformType;°dONLNd5'2*
  7574. 4                       theIconCache: Handle): OSErr;
  7575. °dONLNdj=Iê*This call allows preflight °dONLNdÖ=êI⁄)xDloading of certain elements of your icon cache. This is handy if you°dONLNd IU
  7576. (q62suspect that certain drawing operations may occur °dONLNd¸I
  7577. U⁄)ı)at a time not convenient for loading your°dONLNd&Vbc(~6Ficon data (e.g., when your resource fork might not be in open chain). °dONLNdlUcaæ(~Å
  7578. LoadIconCache°dONLNdyVæb⁄)[ takes°dONLNdÄcoá(ã6the same parameters as °dONLNdóbán‚)o
  7579. PlotIconSuite°dONLNd§c‚o`)[ and uses the same criteria °dONLNd¿c`o⁄)~to select the icon to load.°dONLNd‹o{Y(ó6
  7580. The grafPort °dONLNdÈoY{⁄)APmust be set properly before making this call since it is one of the criteria for°dONLNd:{áü(£6determining the icon to load.°dONLNdX*&The following four calls are provided °dONLNd~î—†)π
  7581. to change °dONLNdàìü6)4theData°dONLNdèî6†J)1 or °dONLNdììJü{)theProc°dONLNdöî{†⁄)1 associated with an°dONLNdƆ¨L(»6 icon cache:
  7582.     °dONLNd∫∏√Ô*+FUNCTION GetIconCacheData(theCache: Handle;°dONLNdÁ¬Õ*
  7583. 3                          VAR theData: Ptr): OSErr;°dONLNdÃ◊Ô*
  7584. +FUNCTION SetIconCacheData(theCache: Handle;°dONLNdH÷·*
  7585. /                          theData: Ptr): OSErr;°dONLNdx‡ÎÔ*
  7586. +FUNCTION GetIconCacheProc(theCache: Handle;°dONLNd•Íı:*
  7587. :                          VAR theProc: IconGetter): OSErr;°dONLNd‡ÙˇÔ*
  7588. +FUNCTION SetIconCacheProc(theCache: Handle;°dONLNd
  7589. ˛    &*
  7590. 6                          theProc: IconGetter): OSErr;
  7591. °dONLNdD ◊*"Plotting Icons Not Part of a Suite°dONLNdg,8*5The next calls are grouped because they are similar. °dONLNdú,8⁄)ˇ'They let you plot an icon to the screen°dONLNdƒ9Em(a6Fwithout your creating an icon suite. They are also good if you have a °dONLNd
  7592. 8mDó(aã'cicn'°dONLNd9óE¿)*     instead °dONLNd9¿E⁄))of an°dONLNdEQQ(m6 icon family.
  7593.     °dONLNd,]h¬*"FUNCTION PlotIconID(theRect: Rect;°dONLNdOgr˘*
  7594. -                    align: IconAlignmentType;°dONLNd}q|
  7595. *
  7596. 1                    transform: IconTransformType;°dONLNdØ{ܲ*
  7597. .                    theResID: INTEGER): OSErr;°dONLNdfièö€*'FUNCTION PlotCIconHandle(theRect: Rect;°dONLNdô§*
  7598. 2                         align: IconAlignmentType;°dONLNd9£Æ&*
  7599. 6                         transform: IconTransformType;°dONLNdp≠∏+*
  7600. 7                         theCIcon: CIconHandle): OSErr;°dONLNd®¡Ã÷*&FUNCTION PlotIconMethod(theRect: Rect;°dONLNdœÀ÷
  7601. *
  7602. 1                        align: IconAlignmentType;°dONLNd’‡!*
  7603. 5                        transform: IconTransformType;°dONLNd7flͲ*
  7604. .                        theMethod: IconGetter;°dONLNdfÈÙ&*
  7605. 6                        yourDataPtr: UNIV Ptr): OSErr;°dONLNdù˝÷*&FUNCTION PlotIconHandle(theRect: Rect;°dONLNdƒ
  7606. *
  7607. 1                        align: IconAlignmentType;°dONLNdˆ!*
  7608. 5                        transform: IconTransformType;°dONLNd,&*
  7609. 0                        theIcon: Handle): OSErr;°dONLNd]/:÷*&FUNCTION PlotSICNHandle(theRect: Rect;°dONLNdÑ9D
  7610. *
  7611. 1                        align: IconAlignmentType;°dONLNd∂CN!*
  7612. 5                        transform: IconTransformType;°dONLNdÏMX*
  7613. 0                        theSICN: Handle): OSErr;
  7614. °dONLNd    dpF*
  7615. All these °dONLNd    'dFp).)routines share the following parameters: °dONLNd    PcoJ) theRect °dONLNd    XdJp⁄):is the destination rectangle to°dONLNd    xq}†(ô6draw the indicated icon into; °dONLNd    ñp†|√)àalign°dONLNd    õq√}‚)# is the °dONLNd    £q‚}⁄)4alignment method to use if the icon does not fit the°dONLNd    ÿ~äe(¶6rectangle given; °dONLNd    È}eâ§)M    transform°dONLNd    Ú~§ä∑)?< indicates the desired appearance of the icon on the screen. ‚4‚˘
  7616. (˜66) of 12(˜qDrawing Icons the System 7 Wayˇx◊#ˇ ˇˇˇˇ#◊ 
  7617. IR,Times
  7618. .+Z-Developer Support Center(-Ê October 1992 /X/
  7619. °dONLNd<*J(FZIn ,
  7620. Courier°dONLNdJ)ê)
  7621. PlotIconID°dONLNd
  7622. ê*‹)F, the parameter °dONLNd‹))LtheResID°dONLNd%*$)8 is °dONLNd)$*…)!the resource ID of the family of °dONLNdJ…)Â)•'ic'°dONLNdNÂ*˛) type°dONLNdT*<6l(RZ
  7623. resources °dONLNd^*l6˛)0Yto use. If the correct bit depth or the size required is not defined, the closest-fitting°dONLNd∏6<Bç(^Zone will be used.°dONLNd O<[T*The °dONLNdŒNTZΩ)PlotCIconHandle°dONLNd›OΩ[˜)i  parameter °dONLNdËN˜Z/):theCIcon°dONLNdO/[N)8 is a °dONLNdˆON[˛)!handle that you get to a standard°dONLNd\<hŒ(ÑZQuickDraw color icon. Unlike °dONLNd5[Œg
  7624. )í    PlotCIcon°dONLNd>\
  7625. h)?, °dONLNd@[g})PlotCIconHandle°dONLNdO\}h´)i
  7626.  does not °dONLNdY\´h˛).honor the current°dONLNdki<u˝(ëZ'foreground and background colors. Call °dONLNdíh˝t5)¡GetCIcon°dONLNdöi5u˛)8) to load the icon. Dispose of it when you°dONLNdƒu<Å>(ùZ7are done, since they can take up quite a bit of memory.°dONLNd¸ç<ôû*PlotIconMethod°dONLNd
  7627. éûö’)b  calls your °dONLNdç’ô)7
  7628. IconGetter°dONLNd éöV)F  procedure, °dONLNd,éVö˛);#discussed earlier, to check for the°dONLNdPö<¶•(¬Zexistence of icon data.°dONLNdi≤<æû*PlotIconHandle°dONLNdw≥ûø )b will plot the data from °dONLNdê≥ ø)nan °dONLNdì≤æE)'ICN#'°dONLNdô≥EøW)* or °dONLNdù≤WæÅ)'ICON'°dONLNd£≥Åø˛)* resource from its handle.°dONLNdæ¿<ã(ËZIt is a new version of °dONLNd’ø£À€)gPlotIcon°dONLNd›¿€Ãfl)8.°dONLNdflÿ<‰û(ZPlotSICNHandle°dONLNdÌŸûÂ)b plots the data of a °dONLNdÿ‰-)e'SICN'°dONLNdŸ-Â2)* °dONLNd    Ÿ2‘)resource from its handle. Only °dONLNd(ÿ‘‰˛)¢'SICN'°dONLNd/Â<Ò¡(
  7629. ZLresources with a single member, or one in which the second member is a mask °dONLNd{Â¡Ò˛(
  7630. flfor the first,°dONLNdäÒ<˝ì(Zwill plot correctly.°dONLNdü    <;*9All the functions return an error code if things did not °dONLNdÿ    ;˛)ˇ(go well with the drawing or, in the case°dONLNd<"Z(>Zof the °dONLNdZ!†)
  7631. PlotIconID°dONLNd†"ë)F6 call, if the indicated icon family could not be used.°dONLNdI.<:≠(VZMiscellaneous Calls
  7632.     °dONLNd]F<Qˇ*'FUNCTION GetLabel(labelNumber: INTEGER;°dONLNdÖP<[*
  7633. +                  VAR labelColor: RGBColor;°dONLNd±Z<e6*
  7634. 2                  VAR labelString: Str255): OSErr;
  7635. °dONLNd‰p<|=*:This call returns the actual color and string used in the °dONLNdp=|˛(ò[(label menu of the Finder and the label’s°dONLNdG|<à(§Z,Control Panel. This information is provided °dONLNds|à˛)“3in case you wish to include the label text or color°dONLNdßà<î#(∞Z2when displaying a file’s icon in your application.
  7636.     °dONLNd⁄†<´**FUNCTION IconSuiteToRgn(theRgn: RgnHandle;°dONLNd™<µˇ*
  7637. '                        iconRect: Rect;°dONLNd-¥<ø1*
  7638. 1                        align: IconAlignmentType;°dONLNd_æ<…E*
  7639. 5                        theIconSuite: Handle): OSErr;°dONLNdï“<›ˇ*'FUNCTION IconIDToRgn(theRgn: RgnHandle;°dONLNdΩ‹<Á*
  7640. $                     iconRect: Rect;°dONLNd‚Ê<Ò"*
  7641. .                     align: IconAlignmentType;°dONLNd<˚*
  7642. -                     iconID: INTEGER): OSErr;°dONLNd?<*+FUNCTION IconMethodToRgn(theRgn: RgnHandle;°dONLNdk<*
  7643. (                         iconRect: Rect;°dONLNdî<#6*
  7644. 2                         align: IconAlignmentType;°dONLNd«"<-'*
  7645. /                         theMethod: IconGetter;°dONLNd˜,<76*
  7646. 2                         yourDataPtr: Ptr): OSErr;
  7647. °dONLNd*C<OÑ*These routines °dONLNd9CÑO±)H?will create a region from the mask of the icon selected by the °dONLNdxB±NÈ(kœiconRect°dONLNdÄCÈO˛)8 and°dONLNdÖO<[_(xZalign°dONLNdäP_\Â)#T values passed. They will allow you to do accurate hit testing and outline dragging °dONLNdfiPÂ\˛(xof an°dONLNd‰]<i{(ÖZ
  7648. icon in your °dONLNdÒ]{iŒ)?application. The °dONLNd    \Œh
  7649. )S    RgnHandle°dONLNd     ]
  7650. i˛)?/ must have been previously allocated before you°dONLNd    ;i<uÄ(ëZmake this call.
  7651.     °dONLNd    KÅ<å*(FUNCTION RectInIconSuite(testRect: Rect;°dONLNd    tã<ñ*
  7652. (                         iconRect: Rect;°dONLNd    ùï<†6*
  7653. 2                         align: IconAlignmentType;°dONLNd    –ü<™T*
  7654. 8                         theIconSuite: Handle): BOOLEAN; ‚X‚
  7655. *1Drawing Icons the System 7 Way(˜ˇ7) of 12ˇ◊#ˇ ˇˇˇˇ#◊ 
  7656. IR,Times
  7657. .+6-Macintosh Technical Notes /4/˘,
  7658. Courier
  7659.     °dONLNd(—*%FUNCTION RectInIconID(testRect: Rect;°dONLNd&'2—*
  7660. %                      iconRect: Rect;°dONLNdL1<*
  7661. /                      align: IconAlignmentType;°dONLNd|;F*
  7662. 0                      iconID: INTEGER): BOOLEAN;°dONLNd≠OZÂ*)FUNCTION RectInIconMethod(testRect: Rect;°dONLNd◊YdÂ*
  7663. )                          iconRect: Rect;°dONLNdcn*
  7664. 3                          align: IconAlignmentType;°dONLNd5mx*
  7665. 0                          theMethod: IconGetter;°dONLNdfwÇ!*
  7666. 5                          yourDataPtr: Ptr): BOOLEAN;°dONLNdúãñ—*%FUNCTION PtInIconSuite(testPt: Point;°dONLNd¬ï†÷*
  7667. &                       iconRect: Rect;°dONLNdÈü™*
  7668. 0                       align: IconAlignmentType;°dONLNd©¥&*
  7669. 6                       theIconSuite: Handle): BOOLEAN;°dONLNdQΩ»¬*"FUNCTION PtInIconID(testPt: Point;°dONLNdt«“«*
  7670. #                    iconRect: Rect;°dONLNdò—‹˘*
  7671. -                    align: IconAlignmentType;°dONLNdΔ€Ê˛*
  7672. .                    iconID: INTEGER): BOOLEAN;°dONLNdıÔ˙÷*&FUNCTION PtInIconMethod(testPt: Point;°dONLNd˘€*
  7673. '                        iconRect: Rect;°dONLNdD
  7674. *
  7675. 1                        align: IconAlignmentType;°dONLNdv
  7676. ˛*
  7677. .                        theMethod: IconGetter;°dONLNd•"*
  7678. 3                        yourDataPtr: Ptr): BOOLEAN;
  7679. °dONLNdŸ-9*.These calls hit test the passed Point or Rect °dONLNd-9⁄)È*against the icon indicated. The parameters°dONLNd29EP(b6iconRect°dONLNd::PFg)8 and °dONLNd?9gEä)align°dONLNdD:äF∏)#@, and the grafPort should be the same as when the icon was last °dONLNdÑ:∏F⁄(b÷drawn.°dONLNdãFR\(n6The functions °dONLNdôF\R⁄)DTreturn true if the point is in the icon mask or if the rectangle intersects the icon°dONLNdÓR^5(z6mask.
  7680. °dONLNdÙvÖk*' Error Codes
  7681. °dONLNdëùõ*RThe Icon Utilities will pass back any errors encountered during execution, so you °dONLNdRëõù⁄(ππ
  7682. can expect to°dONLNd`ù©W(≈6>see Memory Manager, Resource Manager, and other normal errors.°dONLNdüµ¡Æ* There is one error code defined °dONLNdøµÆ¡⁄)ñAspecifically for the Icon Utilities routines that may be returned°dONLNd¡Õ°(È6by the Icon plotting routines.
  7683.     °dONLNd Ÿ‰J*
  7684. { Pascal }°dONLNd+„Ó1*
  7685. CONST°dONLNd2Ì<¯†+$
  7686. noMaskFound = -1000;°dONLNdG˜,(6END;°dONLNdL ;*/* C */°dONLNdT w*
  7687. #define noMaskFound°dONLNdhÑ ù)l-1000
  7688. °dONLNdn+7°(S6This error will be returned if °dONLNdç+°7⁄)âBthe Icon Utilities package could not find or create a mask for the°dONLNd–7C$(_6;icon family.  The Icon Utilities will use the correct mask °dONLNd 7$C⁄(_B(for each icon size, if one is available.°dONLNd5CO(k64If no mask for a specific size is available, a mask °dONLNdiCO⁄)Í,will be created from any mask in the family,°dONLNdñO[ÿ(w6ebut if there are no 1 bit images and no mask in the family, plotting calls will fail with this error.
  7689. °dONLNd¸sÇ*'$Type(def)s and Glue for Pascal and C
  7690. °dONLNd!éö∫* The Pascal and C interfaces are °dONLNdAé∫ö⁄)¢5provided here to copy and paste since the current MPW°dONLNdwö¶n(¬6standard interface °dONLNdäön¶⁄)VOfiles do not contain the glue for these calls. Electronic versions of this note°dONLNd⁄¶≤.(Œ6are °dONLNdfi¶.≤⁄)Mon AppleLink (Developer Support: Developer Services: Technical Documentation: ‚4‚˘
  7691. (˜68) of 12(˜qDrawing Icons the System 7 Wayˇ*◊#ˇ ˇˇˇˇ#◊ 
  7692. IR,Times
  7693. .+Z-Developer Support Center(-Ê October 1992 /X/
  7694. °dONLNd<)/(EZ.Macintosh Technical Notes: Imaging: Graphics: °dONLNd./)˛)Û(Icon Drawing in 7.sit (Stuffit)) and the°dONLNdW)<5â(QZBDeveloper CD (Technical Documentation: Macintosh Technical Notes: °dONLNdô)â5˛(QßImaging: Graphics: Icon°dONLNd±5<AÇ(]ZDrawing in 7).°dONLNd¿M<YŒ*QMPW C, Pascal, and Assembler files also have been submitted to AppleLink and the °dONLNdMŒY˛(uÏ    Developer°dONLNdY<el(ÅZ>CD, but their paths were not known when this note was written.,
  7695. Courier
  7696.     °dONLNdZq<|å*{ Pascal Types }°dONLNdkÖ<êö*FIconAction         =  ProcPtr;  {FUNCTION IconAction(theType: ResType;°dONLNd≤è<ö©*
  7697. I                                                     VAR theIcon: Handle;°dONLNd¸ô<§«*
  7698. O                                                     yourDataPtr: Ptr): OSErr;}°dONLNdL£<Æö*
  7699. FIconGetter         =  ProcPtr;  {FUNCTION IconGetter(theType: ResType;°dONLNdì≠<∏Ã*
  7700. P                                                     yourDataPtr: Ptr): Handle;}°dONLNd‰∑<¬“*
  7701. IconSelectorValue  =  LONGINT;°dONLNd¡<Ó*
  7702. IconAlignmentType  =  INTEGER;°dONLNd"À<÷“*
  7703. IconTransformType  =  INTEGER;°dONLNdAfl<Íá*{ Pascal Glue }°dONLNdQÛ<˛ü*GFUNCTION PlotIconID(theRect: Rect; align: IconAlignmentType; transform:°dONLNdô˝<ñ*
  7704. IconTransformType;°dONLNd¨<"*
  7705. .                    theResID: INTEGER): OSErr;°dONLNd€<ı*
  7706. %         INLINE  $303C, $0500, $ABC9;°dONLNd<&O*
  7707. 7FUNCTION NewIconSuite(VAR theIconSuite: Handle): OSErr;°dONLNd9%<0ı*
  7708. %         INLINE  $303C, $0207, $ABC9;°dONLNd_/<:—*
  7709. QFUNCTION AddIconToSuite(theIconData: Handle; theSuite: Handle; theType: ResType):°dONLNd±9<DZ*
  7710. OSErr;°dONLNd∏C<Nı*
  7711. %         INLINE  $303C, $0608, $ABC9;°dONLNdfiM<XA*
  7712. F°dONLNdflMAXF)U°dONLNd‡MFXK)N°dONLNd·MKXP)C°dONLNd‚MPXU)T°dONLNd„MUXZ)I°dONLNd‰MZX_)O°dONLNdÂM_Xd)N°dONLNdÊMdXi) °dONLNdÁMhXm)G°dONLNdËMmXr)e°dONLNdÈMrXw)t°dONLNdÍMwX|)I°dONLNdÎM|XÅ)c°dONLNdÏMÅXÜ)o°dONLNdÌMÜXã)n°dONLNdÓMãXê)F°dONLNdÔMêXï)r°dONLNdMïXö)o°dONLNdÒMöXü)m°dONLNdÚMüX§)S°dONLNdÛM§X©)u°dONLNdÙM©XÆ)i°dONLNdıMÆX≥)t°dONLNdˆM≥X∏)e°dONLNd˜M∏XΩ)(°dONLNd¯MΩX¬)V°dONLNd˘M¬X«)A°dONLNd˙M«XÃ)R°dONLNd˚MÃX—) °dONLNd¸M–X’)t°dONLNd˝M’X⁄)h°dONLNd˛M⁄Xfl)e°dONLNdˇMflX‰)I°dONLNdM‰XÈ)c°dONLNdMÈXÓ)o°dONLNdMÓXÛ)n°dONLNdMÛX¯)D°dONLNdM¯X˝)a°dONLNdM˝X)t°dONLNdMX)a°dONLNdMX ):°dONLNdM X) °dONLNd    MX)H°dONLNd
  7713. MX)a°dONLNd MX )n°dONLNd M X%)d°dONLNd
  7714. M%X*)l°dONLNdM*X/)e°dONLNdM/X4);°dONLNdM4X9) °dONLNdM9X>)t°dONLNdM>XC)h°dONLNdMCXH)e°dONLNdMHXM)S°dONLNdMMXR)u°dONLNdMRXW)i°dONLNdMWX\)t°dONLNdM\Xa)e°dONLNdMaXf):°dONLNdMfXk) °dONLNdMkXp)H°dONLNdMpXu)a°dONLNdMuXz)n°dONLNdMzX)d°dONLNdMXÑ)l°dONLNd MÑXâ)e°dONLNd!MâXé);°dONLNd"MéXì) °dONLNd#MìXò)t°dONLNd$MòXù)h°dONLNd%MùX¢)e°dONLNd&M¢Xß)T°dONLNd'MßX¨)y°dONLNd(M¨X±)p°dONLNd)M±X∂)e°dONLNd*M∂Xª):°dONLNd,W<bA(~ZR°dONLNd-WAbF)e°dONLNd.WFbK)s°dONLNd/WKbP)T°dONLNd0WPbU)y°dONLNd1WUbZ)p°dONLNd2WZb_)e°dONLNd3W_bd))°dONLNd4Wdbi):°dONLNd5Wibn) °dONLNd6Wnbs)O°dONLNd7Wsbx)S°dONLNd8Wxb})E°dONLNd9W}bÇ)r°dONLNd:WÇbá)r°dONLNd;Wábå);°dONLNd=a<lı(àZ%         INLINE  $303C, $0609, $ABC9;°dONLNdck<vΩ*
  7715. MFUNCTION ForEachIconDo(theSuite: Handle; selector: IconSelectorValue; action:°dONLNd±u<Äs*
  7716. IconAction;°dONLNdΩ<ä,*
  7717. 0                       yourDataPtr: Ptr): OSErr;°dONLNdÓâ<îı*
  7718. %         INLINE  $303C, $060A, $ABC9;°dONLNdì<ûÜ*
  7719. BFUNCTION GetIconSuite(VAR theIconSuite: Handle; theResID: INTEGER;°dONLNdWù<®^*
  7720. :                      selector: IconSelectorValue): OSErr;°dONLNdíß<≤ı*
  7721. %         INLINE  $303C, $0501, $ABC9;°dONLNd∏±<ºΩ*
  7722. MFUNCTION DisposeIconSuite(theIconSuite: Handle; disposeData: BOOLEAN): OSErr;°dONLNdª<Δı*
  7723. %         INLINE  $303C, $0302, $ABC9;°dONLNd,≈<–Æ*
  7724. JFUNCTION PlotIconSuite(theRect: Rect; align: IconAlignmentType; transform:°dONLNdwœ<⁄ñ*
  7725. IconTransformType;°dONLNdäŸ<‰@*
  7726. 4                       theIconSuite: Handle): OSErr;°dONLNdø„<Ó*
  7727. $        INLINE  $303C, $0603, $ABC9;°dONLNd‰Ì<¯ã*
  7728. CFUNCTION MakeIconCache(VAR theHandle: Handle; makeIcon: IconGetter;°dONLNd(˜<E*
  7729. 5                       yourDataPtr: UNIV Ptr): OSErr;°dONLNd^< ı*
  7730. %         INLINE  $303C, $0604, $ABC9;°dONLNdÑ <Æ*
  7731. JFUNCTION LoadIconCache(theRect: Rect; align: IconAlignmentType; transform:°dONLNdœ< ñ*
  7732. IconTransformType;°dONLNd‚<*@*
  7733. 4                       theIconCache: Handle): OSErr;°dONLNd    )<4ı*
  7734. %         INLINE  $303C, $0606, $ABC9;°dONLNd    =3<>|*
  7735. @FUNCTION PlotIconMethod(theRect: Rect; align: IconAlignmentType;°dONLNd    ~=<H∏*
  7736. L                        transform: IconTransformType; theMethod: IconGetter;°dONLNd    ÀG<RJ*
  7737. 6                        yourDataPtr: UNIV Ptr): OSErr;°dONLNd
  7738. Q<\ı*
  7739. %         INLINE  $303C, $0805, $ABC9;°dONLNd
  7740. )[<fÅ*
  7741. AFUNCTION GetLabel(labelNumber: INTEGER; VAR labelColor: RGBColor;°dONLNd
  7742. ke<p6*
  7743. 2                  VAR labelString: Str255): OSErr;°dONLNd
  7744. ûo<zı*
  7745. %         INLINE  $303C, $050B, $ABC9;°dONLNd
  7746. ƒy<Ñ∏*
  7747. LFUNCTION PtInIconID(testPt: Point; iconRect: Rect; align: IconAlignmentType;°dONLNd É<é"*
  7748. .                    iconID: INTEGER): BOOLEAN;°dONLNd @ç<òı*
  7749. %         INLINE  $303C, $060D, $ABC9;°dONLNd fó<¢«*
  7750. OFUNCTION PtInIconSuite(testPt: Point; iconRect: Rect; align: IconAlignmentType;°dONLNd ∂°<¨J*
  7751. 6                       theIconSuite: Handle): BOOLEAN;°dONLNd Ì´<∂ı*
  7752. %         INLINE  $303C, $070E, $ABC9; ‚X‚
  7753. *%Drawing Icons the System 7 Way(˜ˇ9) of 12ˇŒ◊#ˇ ˇˇˇˇ#◊ 
  7754. IR,Times
  7755. .+6-Macintosh Technical Notes /4/˘,
  7756. Courier
  7757.     °dONLNd(®*PFUNCTION PtInIconMethod(testPt: Point; iconRect: Rect; align: IconAlignmentType;°dONLNdQ'2ä*
  7758. J                        theMethod: IconGetter; yourDataPtr: Ptr): BOOLEAN;°dONLNdú1<—*
  7759. %         INLINE  $303C, $090F, $ABC9;°dONLNd¬;F£*
  7760. OFUNCTION RectInIconID(testRect: Rect; iconRect: Rect; align: IconAlignmentType;°dONLNdEP*
  7761. 0                      iconID: INTEGER): BOOLEAN;°dONLNdCOZ—*
  7762. %         INLINE  $303C, $0610, $ABC9;°dONLNdiYd≤*
  7763. RFUNCTION RectInIconSuite(testRect: Rect; iconRect: Rect; align: IconAlignmentType;°dONLNdºcn0*
  7764. 8                         theIconSuite: Handle): BOOLEAN;°dONLNdımx—*
  7765. %         INLINE  $303C, $0711, $ABC9;°dONLNdwÇ∑*
  7766. SFUNCTION RectInIconMethod(testRect: Rect; iconRect: Rect; align: IconAlignmentType;°dONLNdoÅåî*
  7767. L                          theMethod: IconGetter; yourDataPtr: Ptr): BOOLEAN;°dONLNdºãñ—*
  7768. %         INLINE  $303C, $0912, $ABC9;°dONLNd‚ï†≠*
  7769. QFUNCTION IconIDToRgn(theRgn: RgnHandle; iconRect: Rect; align: IconAlignmentType;°dONLNd4ü™˘*
  7770. -                     iconID: INTEGER): OSErr;°dONLNdb©¥—*
  7771. %         INLINE  $303C, $0913, $ABC9;°dONLNdà≥æº*
  7772. TFUNCTION IconSuiteToRgn(theRgn: RgnHandle; iconRect: Rect; align: IconAlignmentType;°dONLNd›Ω»!*
  7773. 5                        theIconSuite: Handle): OSErr;°dONLNd«“—*
  7774. %         INLINE  $303C, $0914, $ABC9;°dONLNd9—‹b*
  7775. BFUNCTION IconMethodToRgn(theRgn: RgnHandle; iconRect: Rect; align:°dONLNd|€Êr*
  7776. IconAlignmentType;°dONLNdèÂÖ*
  7777. I                         theMethod: IconGetter; yourDataPtr: Ptr): OSErr;°dONLNdŸÔ˙—*
  7778. %         INLINE  $303C, $0915, $ABC9;°dONLNdˇ˘g*
  7779. CFUNCTION SetSuiteLabel(theSuite: Handle; theLabel: INTEGER): OSErr;°dONLNdC—*
  7780. %         INLINE  $303C, $0316, $ABC9;°dONLNdi
  7781. *
  7782. 2FUNCTION GetSuiteLabel(theSuite: Handle): INTEGER;°dONLNdú"—*
  7783. %         INLINE  $303C, $0217, $ABC9;°dONLNd¬!,q*
  7784. EFUNCTION GetIconCacheData(theCache: Handle; VAR theData: Ptr): OSErr;°dONLNd+6—*
  7785. %         INLINE  $303C, $0419, $ABC9;°dONLNd.5@]*
  7786. AFUNCTION SetIconCacheData(theCache: Handle; theData: Ptr): OSErr;°dONLNdp?J—*
  7787. %         INLINE  $303C, $041A, $ABC9;°dONLNdñITî*
  7788. LFUNCTION GetIconCacheProc(theCache: Handle; VAR theProc: IconGetter): OSErr;°dONLNd„S^—*
  7789. %         INLINE  $303C, $041B, $ABC9;°dONLNd    ]hÄ*
  7790. HFUNCTION SetIconCacheProc(theCache: Handle; theProc: IconGetter): OSErr;°dONLNdRgr—*
  7791. %         INLINE  $303C, $041C, $ABC9;°dONLNdxq|X*
  7792. @FUNCTION PlotIconHandle(theRect: Rect; align: IconAlignmentType;°dONLNdπ{Üû*
  7793. N                        transform: IconTransformType; theIcon: Handle): OSErr;°dONLNdÖê—*
  7794. %         INLINE  $303C, $061D, $ABC9;°dONLNd.èöX*
  7795. @FUNCTION PlotSICNHandle(theRect: Rect; align: IconAlignmentType;°dONLNdoô§û*
  7796. N                        transform: IconTransformType; theSICN: Handle): OSErr;°dONLNdæ£Æ—*
  7797. %         INLINE  $303C, $061E, $ABC9;°dONLNd‰≠∏]*
  7798. AFUNCTION PlotCIconHandle(theRect: Rect; align: IconAlignmentType;°dONLNd    &∑¬û*
  7799. N                         transform: IconTransformType; theCIcon: CIconHandle):°dONLNd    u¡Ã6*
  7800. OSErr;°dONLNd    |À÷—*
  7801. %         INLINE  $303C, $061F, $ABC9;°dONLNd    ¢ÈÙh*/* C Typedefs */°dONLNd    ≥˝è*Ktypedef pascal OSErr   (*IconAction)(ResType theType, Handle *theIcon, void°dONLNd    ˇ^*
  7802. *yourDataPtr);°dONLNd
  7803. Ö*
  7804. Itypedef pascal Handle  (*IconGetter)(ResType theType, void *yourDataPtr);°dONLNd
  7805. X&Â*
  7806. )typedef unsigned long  IconSelectorValue;°dONLNd
  7807. Ç%0Â*
  7808. )typedef short          IconAlignmentType;°dONLNd
  7809. ¨/:Â*
  7810. )typedef short          IconTransformType;°dONLNd
  7811. ÷CNT* /* C Glue */°dONLNd
  7812. „Wbq*Epascal OSErr PlotIconID(const Rect *theRect, IconAlignmentType align,°dONLNd )all*
  7813. D                        IconTransformType transform, short theResID)°dONLNd nkv«*
  7814. #       =  {0x303C, 0x0500, 0xABC9};°dONLNd íuÄ*
  7815. /pascal OSErr NewIconSuite(Handle *theIconSuite)°dONLNd ¬ä«*
  7816. #       =  {0x303C, 0x0207, 0xABC9};°dONLNd Êâî≠*
  7817. Qpascal OSErr AddIconToSuite(Handle theIconData, Handle theSuite, ResType theType)°dONLNd 8ìû«*
  7818. #       =  {0x303C, 0x0608, 0xABC9};°dONLNd \ù®º*
  7819. Tpascal OSErr GetIconFromSuite(Handle *theIconData, Handle theSuite, ResType theType)°dONLNd ±ß≤«*
  7820. #       =  {0x303C, 0x0609, 0xABC9}; ‚4‚˘
  7821. *)10)
  7822.  of 12(˜qDrawing Icons the System 7 Wayˇ◊#ˇ ˇˇˇˇ#◊ 
  7823. IR,Times
  7824. .+Z-Developer Support Center(-Ê October 1992 /X/,
  7825. Courier
  7826.     °dONLNd<(÷(DZRpascal OSErr ForEachIconDo(Handle theSuite, IconSelectorValue selector, IconAction°dONLNdS'<2_*
  7827. action,°dONLNd[1<<*
  7828. -                           void *yourDataPtr)°dONLNdâ;<FÎ*
  7829. #       =  {0x303C, 0x080A, 0xABC9};°dONLNd≠E<P—*
  7830. Qpascal OSErr GetIconSuite(Handle *theIconSuite, short theResID, IconSelectorValue°dONLNdˇO<Zi*
  7831.     selector)°dONLNd    Y<dÎ*
  7832. #       =  {0x303C, 0x0501, 0xABC9};°dONLNd-c<nü*
  7833. Gpascal OSErr DisposeIconSuite(Handle theIconSuite, Boolean disposeData)°dONLNdum<xÎ*
  7834. #       =  {0x303C, 0x0302, 0xABC9};°dONLNdôw<ǧ*
  7835. Hpascal OSErr PlotIconSuite(const Rect *theRect, IconAlignmentType align,°dONLNd‚Å<å∏*
  7836. L                           IconTransformType transform, Handle theIconSuite)°dONLNd/ã<ñÎ*
  7837. #       =  {0x303C, 0x0603, 0xABC9};°dONLNdSï<†ü*
  7838. Gpascal OSErr MakeIconCache(Handle *theHandle, IconGetter makeIcon, void°dONLNdõü<™}*
  7839.  
  7840. *yourDataPtr)°dONLNd©©<¥Î*
  7841. #       =  {0x303C, 0x0604, 0xABC9};°dONLNdÕ≥<æ§*
  7842. Hpascal OSErr LoadIconCache(const Rect *theRect, IconAlignmentType align,°dONLNdΩ<»∏*
  7843. L                           IconTransformType transform, Handle theIconCache)°dONLNdc«<“Î*
  7844. #       =  {0x303C, 0x0606, 0xABC9};°dONLNdá—<‹©*
  7845. Ipascal OSErr PlotIconMethod(const Rect *theRect, IconAlignmentType align,°dONLNd—€<ʬ*
  7846. N                            IconTransformType transform, IconGetter theMethod,°dONLNd Â<"*
  7847. .                            void *yourDataPtr)°dONLNdOÔ<˙Î*
  7848. #       =  {0x303C, 0x0805, 0xABC9};°dONLNds˘<÷*
  7849. Rpascal OSErr GetLabel(short labelNumber, RGBColor *labelColor, Str255 labelString)°dONLNdΔ<Î*
  7850. #       =  {0x303c, 0x050B, 0xABC9};°dONLNdÍ
  7851. <‡*
  7852. Tpascal Boolean PtInIconID(Point testPt, Rect *iconRect, IconAlignmentType alignment,°dONLNd?<"ˇ*
  7853. '                          short iconID)°dONLNdg!<,Î*
  7854. #       =  {0x303c, 0x060D, 0xABC9};°dONLNdã+<6∏*
  7855. Lpascal Boolean PtInIconSuite(Point testPt, Rect *iconRect, IconAlignmentType°dONLNdÿ5<@n*
  7856.  
  7857. alignment,°dONLNd„?<J1*
  7858. 1                             Handle theIconSuite)°dONLNdI<TÎ*
  7859. #       =  {0x303c, 0x070E, 0xABC9};°dONLNd9S<^Ω*
  7860. Mpascal Boolean PtInIconMethod(Point testPt, Rect *iconRect, IconAlignmentType°dONLNdá]<hn*
  7861.  
  7862. alignment,°dONLNdíg<rö*
  7863. F                              IconGetter theMethod, void *yourDataPtr)°dONLNdŸq<|Î*
  7864. #       =  {0x303c, 0x090F, 0xABC9};°dONLNd˝{<ÜΩ*
  7865. Mpascal Boolean RectInIconID(Rect *testRect, Rect *iconRect, IconAlignmentType°dONLNdKÖ<ên*
  7866.  
  7867. alignment,°dONLNdVè<ö    *
  7868. )                            short iconID)°dONLNdÄô<§Î*
  7869. #       =  {0x303c, 0x0610, 0xABC9};°dONLNd§£<ÆÃ*
  7870. Ppascal Boolean RectInIconSuite(Rect *testRect, Rect *iconRect, IconAlignmentType°dONLNdı≠<∏n*
  7871.  
  7872. alignment,°dONLNd∑<¬;*
  7873. 3                               Handle theIconSuite)°dONLNd4¡<ÃÎ*
  7874. #       =  {0x303c, 0x0711, 0xABC9};°dONLNdXÀ<÷—*
  7875. Qpascal Boolean RectInIconMethod(Rect *testRect, Rect *iconRect, IconAlignmentType°dONLNd™’<‡n*
  7876.  
  7877. alignment,°dONLNdµfl<ͧ*
  7878. H                                IconGetter theMethod, void *yourDataPtr)°dONLNd˛È<ÙÎ*
  7879. #       =  {0x303c, 0x0912, 0xABC9};°dONLNd    "Û<˛∏*
  7880. Lpascal OSErr IconIDToRgn(RgnHandle theRgn, Rect *iconRect, IconAlignmentType°dONLNd    o˝<n*
  7881.  
  7882. alignment,°dONLNd    z<˙*
  7883. &                         short iconID)°dONLNd    °<Î*
  7884. #       =  {0x303c, 0x0613, 0xABC9};°dONLNd    ≈<&«*
  7885. Opascal OSErr IconSuiteToRgn(RgnHandle theRgn, Rect *iconRect, IconAlignmentType°dONLNd
  7886. %<0n*
  7887.  
  7888. alignment,°dONLNd
  7889.  /<:,*
  7890. 0                            Handle theIconSuite)°dONLNd
  7891. Q9<DÎ*
  7892. #       =  {0x303c, 0x0714, 0xABC9};°dONLNd
  7893. uC<NÃ*
  7894. Ppascal OSErr IconMethodToRgn(RgnHandle theRgn, Rect *iconRect, IconAlignmentType°dONLNd
  7895. ΔM<Xn*
  7896.  
  7897. alignment,°dONLNd
  7898. —W<bï*
  7899. E                             IconGetter theMethod, void *yourDataPtr)°dONLNd a<lÎ*
  7900. #       =  {0x303c, 0x0915, 0xABC9};°dONLNd ;k<vc*
  7901. ;pascal OSErr SetSuiteLabel(Handle theSuite, short theLabel)°dONLNd wu<ÄÎ*
  7902. #       =  {0x303C, 0x0316, 0xABC9};°dONLNd õ<ä*
  7903. +pascal short GetSuiteLabel(Handle theSuite)°dONLNd «â<îÎ*
  7904. #       =  {0x303C, 0x0217, 0xABC9};°dONLNd Îì<ûr*
  7905. >pascal OSErr GetIconCacheData(Handle theCache, void **theData)°dONLNd *ù<®Î*
  7906. #       =  {0x303C, 0x0419, 0xABC9};°dONLNd Nß<≤m*
  7907. =pascal OSErr SetIconCacheData(Handle theCache, void *theData) ‚X‚
  7908. *)Drawing Icons the System 7 Way(˜˙11)
  7909.  of 12ˇ¬◊#ˇ ˇˇˇˇ#◊ 
  7910. IR,Times
  7911. .+6-Macintosh Technical Notes /4/˘,
  7912. Courier
  7913.     °dONLNd(«*#       =  {0x303C, 0x041A, 0xABC9};°dONLNd$'2g*
  7914. Cpascal OSErr GetIconCacheProc(Handle theCache, IconGetter *theProc)°dONLNdh1<«*
  7915. #       =  {0x303C, 0x041B, 0xABC9};°dONLNdå;Fb*
  7916. Bpascal OSErr SetIconCacheProc(Handle theCache, IconGetter theProc)°dONLNdœEP«*
  7917. #       =  {0x303C, 0x041C, 0xABC9};°dONLNdÛOZÖ*
  7918. Ipascal OSErr PlotIconHandle(const Rect *theRect, IconAlignmentType align,°dONLNd=YdÄ*
  7919. H                            IconTransformType transform, Handle theIcon)°dONLNdÜcn«*
  7920. #       =  {0x303C, 0x061D, 0xABC9};°dONLNd™mxÖ*
  7921. Ipascal OSErr PlotSICNHandle(const Rect *theRect, IconAlignmentType align,°dONLNdÙwÇÄ*
  7922. H                            IconTransformType transform, Handle theSICN)°dONLNd=Åå«*
  7923. #       =  {0x303C, 0x061E, 0xABC9};°dONLNdaãñä*
  7924. Jpascal OSErr PlotCIconHandle(const Rect *theRect, IconAlignmentType align,°dONLNd¨ï†£*
  7925. O                             IconTransformType transform, CIconHandle theCIcon)°dONLNd¸ü™«*
  7926. #       =  {0x303C, 0x061F, 0xABC9};
  7927. °dONLNd ÕŸÇ*/Further Reference: ¯4¯˘°dONLNd3⁄*Ê.+
  7928. •°dONLNd5⁄<Êç)Inside Macintosh°dONLNdE⁄çÊ&)Q, Volume V, QuickDraw chapter°dONLNdcÊ*Ú.(H•°dONLNdeÊ<Úç)Inside Macintosh°dONLNduÊçÚ?)Q%, Volume VI, Finder Interface chapter ‚4‚˘
  7929. (˜612)
  7930.  of 12(˜qDrawing Icons the System 7 WayˇÊ◊#ˇ ˇˇˇˇ#◊†Ç 
  7931. /_Å(
  7932.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  7933. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  7934. .R…R…+bBNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  7935. ({öDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  f!f_°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  7936. 0(UÙ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  7937.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  7938. (Za    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  7939. d.°dONLNdn<Å)(õZDisplaying Large PICT Files
  7940. °dONLNdÄ<èr*Imaging°dONLNd%Äìè˛(´±M.IM.LargePict
  7941. °dONLNd4õ<ßt(√Z Revised by:°dONLNdAõ≈߲(√„
  7942. March 1988°dONLNdLß<≥q(œZ Written by:°dONLNdXßÑ≥∑)H Rick Blair °dONLNddßœ≥˛(œÌ    July 1987°dONLNdnø<À (ÁZ^Now that we have scanners and other massive-picture producing types of applications, there is °dONLNdÃø À(Á)a°dONLNdŒÀ<◊U(ÛZneed °dONLNd”ÀU◊)[to address the problem of how to display a PICT format object that is bigger than a current°dONLNd/◊<„í(ˇZPICT resource is °dONLNd@◊í„)VMallowed to be. Note that this technique applies equally well to version 1 and°dONLNdé„<Ôy( ZAversion 2 (word-opcode) pictures as produced by the Macintosh II. X/
  7943. °dONLNd–<#»*4Future Compatibility
  7944. °dONLNdÂ0<<‡* Think of the handle returned by °dONLNd0‡<Î)§a ,
  7945. Courier°dONLNd/Î;Ö) GetResource('PICT',ID)°dONLNd0Ö<)ö as a “handle” in the more°dONLNd8<<Hc(dZ<general sense of being an abstract “tag”—something that the °dONLNdt<cH(dÅ ROM routines can use to draw the°dONLNdïH<Tî(pZFpicture with. Don’t assume that the entire picture has been read into °dONLNd€HîT(p≤memory or that you can°dONLNdÚU<ad(}Z    directly °dONLNd˚Uda)( read any bytes beyond the basic °dONLNdT`@)´Picture°dONLNd"U@aù)1 record structure (°dONLNd5Tù`Œ)]picSize°dONLNd<UŒa)1  followed by°dONLNdIa<mt(äZpicFrame°dONLNdQbtnK)8&). Someday we may provide a mechanism °dONLNdwbKn)◊'for the resource to be disk- instead of°dONLNdün<z\(ñZ7memory-based. The QuickDraw bottleneck procedures will °dONLNd÷n\z(ñz!know how to get data from and put°dONLNd¯z<Üÿ(¢Z#data into the pictures in any case.
  7946. °dONLNdû<≠Ï*'Spooling from a PICT file
  7947. °dONLNd6π<≈¢*In order to display °dONLNdJπ¢≈)fGpictures of arbitrary size, your application should be able to import a°dONLNdí≈<—µ(ÌZQuickDraw picture from °dONLNd©≈µ—)yCa file of type PICT. This is the file produced by a “Save as…” from°dONLNdÌ—<›˝(˘Z&MacDraw with the PICT option selected.°dONLNdÈ<ı‚*UWhat follows is a small program fragment that demonstrates how to spool in a picture °dONLNdiÈ‚ı(    from [the°dONLNdsı<S(Zdata °dONLNdxıS)Zfork of] a PICT file. The picture can be larger than the historical 32K resource size. See°dONLNd”<ù(*Ztechnical note #88 °dONLNdÊùA)aif you are unfamiliar with the °dONLNdA
  7948. k)§Signal°dONLNd k)* mechanism. We assume that a°dONLNd(<ê(7Z CatchSignals°dONLNd4ê˙)T has been done before °dONLNdJ˙x)jGetandDrawPICTFile
  7949. °dONLNd\x{)~ 
  7950. °dONLNd]{•)
  7951. is called.
  7952. °dONLNdh3<BÃ(^ZMPW Pascal Example
  7953.     °dONLNd|N`YU+$1{the following variable must be at the top level}°dONLNdØb`mo*VAR°dONLNd¥l`w†*
  7954. @   globalRef   : INTEGER;      {refNum of the file to read from} ¶X¶/
  7955. (ªZDisplaying Large PICT Files(ª1) of 5ˇ°¿Ù%%DSIDICT:_cv
  7956. currentdict /bu known {bu}if
  7957. userdict /_cv known not{userdict /_cv 30 dict put}if
  7958. _cv begin
  7959. /bdf{bind def}bind def
  7960. currentscreen/cs exch def/ca exch def/cf exch def
  7961. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  7962. /ss{//cf //ca //cs setscreen}bdf
  7963. /stg{ss setgray}bdf
  7964. /strgb{ss setrgbcolor}bdf
  7965. /stcmyk{ss cvcmyk}bdf
  7966. /min1{dup 0 eq{pop 1}if}bdf
  7967. end
  7968. currentdict /bn known {bn}if
  7969. †ø  ◊#ˇ ˇˇˇˇ#◊ 
  7970. d,Times
  7971. .+6-Macintosh Technical Notes /4/ ,
  7972. Courier
  7973.     °dONLNd'<26+$!2{the following procedure must be at the top level}°dONLNd4;<FT*8PROCEDURE GetPICTData(dataPtr: Ptr; byteCount: INTEGER);°dONLNdnE<P6*
  7974. 2{replacement for the QuickDraw bottleneck routine}°dONLNd¢Y<dZ*   VAR°dONLNd™c<næ*
  7975.       err         : OSErr;°dONLNdΔm<x»*
  7976.       longCount   : LONGINT;°dONLNd‰Å<åd*   BEGIN°dONLNdÓã<ñÕ*
  7977.       longCount := byteCount;°dONLNd
  7978. ï<†1*
  7979. 1      err := FSRead(globalRef,longCount,dataPtr);°dONLNd@ü<™ü*
  7980. G      {can't check for an error because we don't know how to handle it}°dONLNdâ©<¥_*
  7981.    END;°dONLNdíΩ<»U*CONST°dONLNdô«<“Ü*
  7982. B   abortPICT    = 128;         {error code if DrawPicture aborted}°dONLNd›€<Ê©*IPROCEDURE GetDrawPICTFile;     {read in a PICT FILE selected by the user}°dONLNd(Ô<˙Z*   VAR°dONLNd0˘<T*
  7983. 8      wher        : Point;     {where to display dialog}°dONLNdj<*
  7984. -      reply       : SFReply;   {reply record}°dONLNdô
  7985. <h*
  7986. <      myFileTypes : SFTypeList; {more Standard FILE goodies}°dONLNd◊<"»*
  7987.       numFileTypes: INTEGER;°dONLNdı+<6◊*      savedProcs  : QDProcsPtr;°dONLNd5<@|*
  7988. @      myProcs     : QDProcs;   {use CQDProcs for a color window}°dONLNdXI<T©*I      myPicture   : PicHandle; {we need a picture handle for DrawPicture}°dONLNd£S<^»*
  7989.       longCount   : LONGINT;°dONLNd¡]<h»*
  7990.       myEOF       : LONGINT;°dONLNdflg<r»*
  7991.       myFilePos   : LONGINT;°dONLNd˝{<Üd*   BEGIN°dONLNdÖ<êõ*
  7992.       wher.h := 20;°dONLNdè<öõ*
  7993.       wher.v := 20;°dONLNd1ô<§;*
  7994. 3      numFileTypes := 1;       {display PICT files}°dONLNdf£<Æ◊*
  7995.       myFileTypes[0] := 'PICT';°dONLNdá≠<∏|*
  7996. @      SFGetFile(wher,'',NIL,numFileTypes,myFileTypes,NIL,reply);°dONLNd…¡<Ó*      IF reply.good THEN BEGIN°dONLNdÈÀ<÷Å*
  7997. A         SetStdProcs(myProcs); {use SetStdCProcs for a CGrafPort}°dONLNd,’<‡*
  7998. ,         myProcs.getPicProc := @GetPICTData;°dONLNdZfl<Íö*
  7999. F         savedProcs := thePort^.grafProcs; {set the grafProcs to ours}°dONLNd¢È<Ù*
  8000. (         thePort^.grafProcs := @myProcs;°dONLNdÃ˝<r*>         myPicture := PicHandle(NewHandle(SizeOf(myPicture)));°dONLNd <m*=         Signal(FSOpen(reply.fname,reply.vRefNum,globalRef));°dONLNdK<&ã*
  8001. C         Signal(GetEOF(globalRef,myEOF)); {get EOF for later check}°dONLNdê%<0Ü*
  8002. B         Signal(SetFPos(globalRef,fsFromStart,512)); {skip header}°dONLNd‘9<Dh*<         {read in the (obsolete) size word and the picFrame}°dONLNdC<N*
  8003. (         longCount := SizeOf(myPicture);°dONLNd<M<Xm*
  8004. =         Signal(FSRead(globalRef,longCount,Ptr(myPicture^)));°dONLNd{a<l§*H         DrawPicture(myPicture,myPicture^^.picFrame); {draw the picture} ¶4¶ 
  8005. (ª62) of 5(ª≤Large PICT Filesˇ◊#ˇ ˇˇˇˇ#◊ 
  8006. d,Times
  8007. .+Z-ãDeveloper Support Center                                                                                                       October 1990 /X//,
  8008. Courier
  8009.     °dONLNd)`4π+$#E         Signal(GetFPos(globalRef,filePos)); {get position for check}°dONLNdG3`>*
  8010. $         Signal(FSClose(globalRef));°dONLNdmG`R-*)         DisposHandle(Handle(myPicture));°dONLNdò[`fñ*>         thePort^.grafProcs := savedProcs; {restore the procs}°dONLNdÿo`z}*9         {Check for errors. If there wasn't enough room,}°dONLNdy`Ñ}*
  8011. 9         {DrawPicture will abort; the FILE position mark}°dONLNdNÉ`é7*
  8012. +         {won't be at the end of the FILE.}°dONLNd{ç`òd*
  8013. 4         IF filePos <> myEOF THEN Signal(abortPICT);°dONLNd±ó`¢‚*
  8014.       END; {IF reply.good}°dONLNdÕ°`¨›*
  8015.    END; {GetDrawPICTFile}
  8016. °dONLNdÁ√<“≠(ÓZ
  8017. MPW C Example
  8018.     °dONLNdıfi<È@*4/*replacement for the QuickDraw bottleneck routine*/°dONLNd*Ë<Û*
  8019. *pascal void GetPICTData(dataPtr,byteCount)°dONLNdUÚ<˝K*
  8020. Ptr°dONLNd[Ú®˝–)ldataPtr;°dONLNde¸<U(#Zshort°dONLNdm¸®⁄)l
  8021. byteCount;°dONLNdx<%õ(AZ{ /* GetPICTData */°dONLNdç$`/y+$
  8022. OSErr°dONLNdï$Ã/‡)lerr;°dONLNdõ.`9t(U~long°dONLNd¢.Ã9˛)l
  8023. longCount;°dONLNdÆB`MŒ(i~longCount = byteCount;°dONLNdΔL`W7*
  8024. +err = FSRead(globalRef,&longCount,dataPtr);°dONLNdÛV`aØ*
  8025. C/*can't check for an error because we don't know how to handle it*/°dONLNd7`<kõ(áZ} /* GetPICTData */°dONLNdKt<ı*%/*error code if DrawPicture aborted*/°dONLNdq~<â_*
  8026. #define°dONLNdy~ÑâË)H   abortPICT     128°dONLNdóí<ùØ(πZOSErr GetDrawPICTFile()°dONLNd∞íùÃ)¥,/*read in a PICT FILE selected by the user*/°dONLNd›¶<±A(ÕZ{°dONLNdfl¶`±…)$/* GetDrawPICTFile */°dONLNd˘∫`≈~*Point °dONLNd∫®≈Δ)Hwher; °dONLNd    ∫≈w)H/*where to display dialog*/°dONLNd&ƒ`œÉ(Î~SFReply°dONLNd.ƒ®œ–)Hreply;  °dONLNd7ƒœ@)H/*reply record*/°dONLNdIŒ`Ÿí(ı~
  8027. SFTypeList°dONLNdTŒ®Ÿ‰)H myFileTypes;°dONLNdaŒŸÜ)H/*more Standard FILE goodies*/°dONLNdÅÿ`„~(ˇ~short °dONLNdâÿ®„È)H
  8028. numFileTypes;°dONLNdò‚`Ìy(    ~OSErr°dONLNdü‚®̺)Herr;°dONLNd•Ï`˜í(~
  8029. QDProcsPtr°dONLNd∞Ï®˜fl)H savedProcs;°dONLNdΩˆ`É(~QDProcs°dONLNd≈ˆ®–)HmyProcs;°dONLNdŒˆü)H#/*use CQDProcs for a color window*/°dONLNdÛ` ç('~    PicHandle°dONLNd˝® ⁄)H
  8030. myPicture;°dONLNd Ã)H,/*we need a picture handle for DrawPicture*/°dONLNd6
  8031. `t(1~long°dONLNd<
  8032. ® )HlongCount,myEOF,filePos;°dONLNdV`)∫(E~      wher.h = 20;°dONLNdj(`3∫*
  8033.       wher.v = 20;°dONLNd~2`=ˆ*
  8034.       numFileTypes = 1;       °dONLNdü2\= )¸/*display PICT files*/°dONLNd∑<`Gˆ(c~      myFileTypes[0] = 'PICT';°dONLNd◊F`Q•*
  8035. A      SFGetFile(wher,'',nil,numFileTypes,myFileTypes,nil,&reply);°dONLNdZ`e…*      if (reply.good)°dONLNd4dÑoâ+$
  8036. {°dONLNd9n®y+$
  8037. SetStdProcs(&myProcs); ¶X¶/
  8038. (ªZLarge PICT Files(ª3) of 5ˇ÷◊#ˇ ˇˇˇˇ#◊ 
  8039. d,Times
  8040. .+6-Macintosh Technical Notes /4/ ,
  8041. Courier
  8042.     °dONLNdÑ(8+l$/*use SetStdCProcs for a CGrafPort*/°dONLNd&'<2i(NZ             °dONLNd0'Ñ2))H!myProcs.getPicProc = GetPICTData;°dONLNdS1<<i(XZ             °dONLNd]1Ñ<=)H%savedProcs = (*qd.thePort).grafProcs;°dONLNdÜEÑP*/*set the grafProcs to ours*/°dONLNd•O<Zi(vZ             °dONLNdØOÑZ3)H#(*qd.thePort).grafProcs = &myProcs;°dONLNd‘c<ni(äZ             °dONLNdficÑn~)H2myPicture = (PicHandle)NewHandle(sizeof(Picture));°dONLNdwÑÇà*4err = FSOpen(&reply.fName,reply.vRefNum,&globalRef);°dONLNdLÅÑå*
  8043. if (err != noErr) return err;°dONLNdkï<†U(ºZ     °dONLNdqï`†e)$ °dONLNdsïц)$err = GetEOF(globalRef,&myEOF);°dONLNdñüÑ™ *
  8044. /*get EOF for later check*/°dONLNdµ©Ñ¥*
  8045. if (err != noErr) return err;°dONLNd÷ΩÑ»ú*8err = SetFPos(globalRef,fsFromStart,512);/*skip header*/°dONLNd«<“i(ÓZ             °dONLNd«Ñ“)Hif (err != noErr) return err;°dONLNd9€<Êi(Z             °dONLNdC€ÑÊç)H5/*read in the (obsolete) size word and the picFrame*/°dONLNdzÂ<i( Z             °dONLNdÑÂÑ)HlongCount = sizeof(Picture);°dONLNd¢Ô<˙d(Z        °dONLNd´ÔÑ˙à)H4 err = FSRead(globalRef,&longCount,(Ptr)*myPicture);°dONLNd·˘<i( Z             °dONLNd΢Ñ)Hif (err != noErr) return err;°dONLNd
  8046. 
  8047. <i(4Z             °dONLNd
  8048. Ñó)H7DrawPicture(myPicture,&(**myPicture).picFrame); /*draw °dONLNdS"1+l
  8049.  
  8050. the picture*/°dONLNdd+Ñ6ç(R¢5err = GetFPos(globalRef,&filePos);/*get position for °dONLNd°5@+l
  8051. check*/°dONLNd™?<Ji(fZ             °dONLNd¥?ÑJ)Hif (err != noErr) return err;°dONLNd”I<Ti(pZ             °dONLNd›IÑT)Herr = FSClose(globalRef);°dONLNd¯S<^i(zZ             °dONLNdSÑ^)Hif (err != noErr) return err;°dONLNd!g<ri(éZ             °dONLNd+gÑr$)H DisposHandle((Handle)myPicture);°dONLNdM{<Üi(¢Z             °dONLNdW{ÑÜÉ)H3(*qd.thePort).grafProcs = savedProcs;/*restore the °dONLNdíÖê+l
  8052. procs*/°dONLNdõô<§d(¿Z        °dONLNd§ôѧÉ)H3 /*Check for errors. if there wasn't enough room,*/°dONLNdŸ£<Æd( Z        °dONLNd‚£ÑÆÉ)H3 /*DrawPicture will abort; the FILE position mark*/°dONLNd≠<∏i(‘Z             °dONLNd!≠Ñ∏8)H$/*won't be at the end of the FILE.*/°dONLNdI¡ÑÃL*(if (filePos != myEOF)  return abortPICT;°dONLNduÀÑ÷fi*
  8053. else return noErr;°dONLNdâ’<‡»(¸Z      } /*if (reply.good) */°dONLNd¶flÍ"(6} °dONLNd©fl<Í•)$/* GetDrawPICTFile */
  8054. °dONLNdøÂ(,6More on Picture Compatibility
  8055. °dONLNd›(6*Many °dONLNd‚6(Ï)Vapplications already support PICT resources larger than 32K. The 128K ROMs (and later)°dONLNd9(4(P60allow pictures as large as memory (or spooling) °dONLNdi(4Ï)Ï+will accommodate. This was made possible by°dONLNdï4@q(\6Hhaving QuickDraw ignore the size word and simply read the picture until °dONLNd›4q@Ï(\èthe end-of-picture opcode°dONLNd˜@LV(h6 was reached.°dONLNdXd√*WFor maximum safety and convenience, let QuickDraw generate and interpret your pictures. ¶4¶ 
  8056. *;4) of 5(ª≤Large PICT Filesˇ Ä◊#ˇ ˇˇˇˇ#◊ 
  8057. d,Times
  8058. .+Z-ãDeveloper Support Center                                                                                                       October 1990 /X//
  8059. °dONLNdˇˇ*$JWhile Apple has provided you with the data formats that allow you to read °dONLNdˇˇ(Q or write picture data°dONLNdˇˇ(]Z+directly, we recommend that you always let °dONLNdˇˇ)–3DrawPicture or OpenPicture and ClosePicture process°dONLNdˇˇ(iZ the opcodes.°dONLNdˇˇ*VOne reason to read a picture directly by scanning the opcodes would be to disassemble °dONLNdˇˇ(Å
  8060. it to, for°dONLNdˇˇ(çZVexample, extract a Color QuickDraw pixel map to save off in a private data structure. °dONLNdˇˇ(çThis°dONLNdˇˇ(ôZ shouldn’t normally be necessary.°dONLNdˇˇ*+If you do look at the picture data be sure °dONLNdˇˇ)¡6and check the version information. You may want to put°dONLNdˇˇ(ΩZJup an alert in your application that indicates to the user when a picture °dONLNdˇˇ(Ω≥was created using a later°dONLNdˇˇ(…ZWversion of the picture format than your application recognizes, letting them know that °dONLNdˇˇ(…some°dONLNdˇˇ(’Z<elements of the picture cannot be displayed. If the version °dONLNdˇˇ(’Å!information indicates a QuickDraw°dONLNdˇˇ(·Zpicture °dONLNdˇˇ)#Xversion later than the one recognized by your application, your program should skip over°dONLNdˇˇ(ÌZ<the new opcodes and only attempt to parse the ones it knows.°dONLNdˇˇ*MAs with reading picture data directly, it is best to use QuickDraw to create °dONLNdˇˇ(∑data in the PICT format.°dONLNdˇˇ(Z4If you do need to create PICT format data directly, °dONLNdˇˇ)˚.it is essential that you use the latest opcode°dONLNdˇˇ(ZAspecifications and that you thoroughly test the data produced on °dONLNdˇˇ(ìboth color and black and white°dONLNdˇˇ()Z:Macintosh machines. Contact Macintosh Developer Technical °dONLNdˇˇ()$Support if you are not sure that you°dONLNdˇˇ(5Zhave the latest specifications.°dONLNdˇˇ*UApple does not guarantee that a picture which wasn’t produced by QuickDraw will work.°dONLNdˇˇ*0Further Reference: ÄXÄ/°dONLNdˇˇ+
  8061. •°dONLNdˇˇ)    QuickDraw°dONLNdˇˇ(ñl•°dONLNdˇˇ)$Technical Note M.IM.PictureOpcodes —°dONLNdˇˇ+$ Internal Picture Format°dONLNdˇˇ(Æl•°dONLNdˇˇ)Technical Note M.PT.Signals —°dONLNdˇˇ+$ Signals ¶X¶/
  8062. (ªZLarge PICT Files(ª5) of 5ˇ˙◊#ˇ ˇˇˇˇ#◊†Ç 
  8063. /ZÅ#
  8064.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  8065. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  8066. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  8067. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  8068. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  8069.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  8070. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  8071. IR.°dONLNdn<Å(õZLaserWriter Utility Q&As
  8072. °dONLNdÄ<èr*Imaging°dONLNd!Äuè˛(´ìM.IM.LWUtil.Q&As
  8073. °dONLNd2õ<ßt(√Z Revised by:°dONLNd>õÑߡ)HDeveloper Support Center°dONLNdWõæß˛(√‹ October 1992°dONLNddß<≥q(œZ Written by:°dONLNdpßÑ≥ˇ)HDeveloper Support Center°dONLNdâßæ≥˛(œ‹ October 1990°dONLNdñø<À⁄(ÁZThis Technical Note contains a °dONLNdµø⁄À˛)û9collection of Q&As relating to a specific topic—questions°dONLNdÔÀ<◊†(ÛZGyou’ve sent the Developer Support Center (DSC) along with answers from °dONLNd6À†◊˛(Ûæthe DSC engineers.°dONLNdI◊<„u(ˇZ
  8074. While DSC °dONLNdS◊u„˛)9Lengineers have checked the Q&A content for accuracy, the Q&A Technical Notes°dONLNd†„<Ôq( Z don’t have °dONLNd´„qÔ˛)5Qthe editing and organization of other Technical Notes. The Q&A function is to get°dONLNd˝Ô<˚Ÿ(Znew technical information and °dONLNdÔŸ˚˛)ù6updates to you quickly, saving the polish for when the°dONLNdR˚<(#Z,information migrates into reference manuals.°dONLNd<k*:Q&As are now included with Technical Notes to make access °dONLNdπk˛(;âto technical updates easier for°dONLNdŸ<+.(GZ/you. If you have comments or suggestions about °dONLNd.+˛)Ú*Q&A content or distribution, please let us°dONLNd3+<7\(SZknow °dONLNd8+\7˛) Iby sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical°dONLNdÇ7<Ci(_Z9questions about Q&A content to DEVSUPPORT for resolution.°dONLNdºO<[«*NNew Q&As and Q&As revised this month are marked with a bar in the side margin."n  ÜXÜ
  8075. °dONLNd Ä<è‹*49SCSI drive format for LaserWriter II NTX with Rev. 3 ROMs
  8076. °dONLNdEè<õb* Written:°dONLNdNèàõ¶)L5/3/91°dONLNdUõ<ßÅ(√ZLast reviewed:°dONLNddõàߨ)L6/26/91°dONLNdl≥<øW(€Z<What could be causing intermittent PostScript errors from a °dONLNd®≥Wø˛(€uLaserWriter II NTX with an SCSI°dONLNd»ø<ÀU(ÁZ9hard disk mounted after installing the Rev 3 ROM upgrade?°dONLNdÀ<◊N* ___°dONLNd„<Ô~*>The LaserWriter II NTX with Rev 3 ROMs does not work properly °dONLNdD„~Ô˛( úwith a hard disk formatted°dONLNd_Ô<˚e(Z    with the °dONLNdhÔe˚˛))SLaserWriter Font Utility 1.x. You need to reformat the disk and copy the fonts back°dONLNdº˚<¬(#Zonto the hard disk using the °dONLNdŸ˚¬˛)ÜALaserWriter Font Utility 2.0.2. Unfortunately, there is no way to°dONLNd<Ω(/Zmake this procedure easier.
  8077. °dONLNd7+<:π*':LaserWriter Font Utility copies Postscript file to printer
  8078. °dONLNdr:<Fb* Written:°dONLNd{:àF¨)L9/23/91°dONLNdÉF<RÅ(nZLast reviewed:°dONLNdíFàR¨)L10/8/91°dONLNdö^<j£(ÜZQIs there a utility that will send a PostScript file from disk to the LaserWriter?°dONLNdÏj<vN* ___°dONLNdÇ<éé*The LaserWriter °dONLNdÇéé˛)RJFont Utility handles this job and is part of the System 7 disk set. On the°dONLNdKé<öÀ(∂ZSystem 7 Golden Master CD, °dONLNdféÀö˛)è?the path is System 7.0: System Software 7.0: Installer Version:°dONLNd¶ö<¶Ä(¬ZTidbits folder. ◊X◊
  8079. **LaserWriter Font Utility Q&As(Ï1) of 1ˇ°¿Ù%%DSIDICT:_cv
  8080. currentdict /bu known {bu}if
  8081. userdict /_cv known not{userdict /_cv 30 dict put}if
  8082. _cv begin
  8083. /bdf{bind def}bind def
  8084. currentscreen/cs exch def/ca exch def/cf exch def
  8085. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  8086. /ss{//cf //ca //cs setscreen}bdf
  8087. /stg{ss setgray}bdf
  8088. /strgb{ss setrgbcolor}bdf
  8089. /stcmyk{ss cvcmyk}bdf
  8090. /min1{dup 0 eq{pop 1}if}bdf
  8091. end
  8092. currentdict /bn known {bn}if
  8093. †ø∞◊#ˇ ˇˇˇˇ#◊°d WORDS †å°d WORDR…†Ç 
  8094. /_Å(
  8095.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  8096. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  8097. .eRSeRS+bBNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  8098. Ä({öDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  f!f_°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  8099. 0(UÙ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  8100.     l+&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  8101. BÄ(Za    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É°dWORD†ç
  8102. d.°dONLNdc<vc(êZ!Drawing Into an Off-Screen Bitmap
  8103. °dONLNd"u<Ñr*Imaging°dONLNd*ucÑ˛(†ÅM.IM.OffscreenBitMap
  8104. °dONLNd?ê<út(∏Z Revised by:°dONLNdKêÑú)HJon Zap & Forrest Tanaka°dONLNddêÕú˛(∏Π   June 1990°dONLNdnú<®q(ƒZ Written by:°dONLNdzúÑ®))H!Jim Friedlander & Ginger Jernigan°dONLNdúúœ®˛(ƒÌ    July 1985°dONLNd¶¥<¿E(‹Z7This Technical Note provides an example of creating an °dONLNd›¥E¿(‹c*off-screen bitmap, drawing to it, and then°dONLNd¿<ë(ËZcopying from it to the screen.°dONLNd'Ã<ÿ“* Changes since April 1990:°dONLNd@Óÿ)ñ   Clarified °dONLNdLÃÿ)25the section on window updates with off-screen bitmaps°dONLNdÇÿ<‰=(Z6to explicitly limit these updates to your own windows. X/°dONLNdπ˝<    Ö*%EThe following is an example of creating and drawing to an off-screen °dONLNd˛˝Ö    (%£bitmap, then copying from it°dONLNd    <∞(1ZIto an on-screen window.  We supply this example in both MPW Pascal and C.°dONLNde!<-É*
  8105. MPW Pascal°dONLNdp9<E=*:First, let’s look at a general purpose function to create °dONLNd™9=E(a[,an off-screen bitmap.  This function creates°dONLNd◊F<RO(nZthe ,
  8106. Courier°dONLNd€EOQá)GrafPort°dONLNd„FáRs)8/ on the heap.  You could also create it on the °dONLNdFsR)Ï stack and pass the uninitialized°dONLNd3R<^˛(zZ,structure to a function similar to this one.
  8107.     °dONLNd`j<u÷*RFUNCTION CreateOffscreenBitMap(VAR newOffscreen:GrafPtr; inBounds:Rect) : BOOLEAN;°dONLNd≥~<âK*VAR°dONLNd∑à<ì™*
  8108.   savePort  : GrafPtr;°dONLNdŒí<ù™*
  8109.   newPort   : GrafPtr;°dONLNd¶<±U*BEGIN°dONLNdÎ∞<ª‡*
  8110. T  GetPort(savePort);        {need this to restore thePort after OpenPort changes it}°dONLNd@ƒ<œÆ*J  newPort := GrafPtr(NewPtr(sizeof(GrafPort)));    {allocate the GrafPort}°dONLNdãŒ<Ÿ·*
  8111. !  IF MemError <> noErr THEN BEGIN°dONLNd≠ÿ<„Æ*
  8112. J    CreateOffscreenBitMap := false;                {failed to allocate it}°dONLNd¯‚<Ì‹*
  8113.      EXIT(CreateOffscreenBitMap);°dONLNdÏ<˜Z*
  8114.   END;°dONLNd ˆ<K*
  8115.   {°dONLNd$< *
  8116. ,  the OpenPort call does the following . . .°dONLNdR
  8117. <Â*
  8118. U    allocates space for visRgn (set to screenBits.bounds) and clipRgn (set wide open)°dONLNd®<◊*
  8119.     sets portBits to screenBits°dONLNd»<)˙*
  8120. &    sets portRect to screenBits.bounds°dONLNdÔ(<3√*
  8121.     etc. (see IM I-163,164)°dONLNd 2<=*
  8122. *    side effect: does a SetPort(offScreen)°dONLNd6<<GK*
  8123.   }°dONLNd:F<Q†*
  8124.   OpenPort(newPort);°dONLNdOP<[ã*
  8125. C  {make bitmap exactly the size of the bounds that caller supplied}°dONLNdìZ<eü*
  8126. G  WITH newPort^ DO BEGIN {portRect, clipRgn, and visRgn are in newPort}°dONLNd€d<oπ*
  8127.     portRect := inBounds;°dONLNdın<y∏*
  8128. L    RectRgn(clipRgn, inBounds);        {avoid wide-open clipRgn, to be safe} ¶X¶/
  8129. *&!Drawing Into an Off-Screen Bitmap(ª1) of 6ˇ°¿Ù%%DSIDICT:_cv
  8130. currentdict /bu known {bu}if
  8131. userdict /_cv known not{userdict /_cv 30 dict put}if
  8132. _cv begin
  8133. /bdf{bind def}bind def
  8134. currentscreen/cs exch def/ca exch def/cf exch def
  8135. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  8136. /ss{//cf //ca //cs setscreen}bdf
  8137. /stg{ss setgray}bdf
  8138. /strgb{ss setrgbcolor}bdf
  8139. /stcmyk{ss cvcmyk}bdf
  8140. /min1{dup 0 eq{pop 1}if}bdf
  8141. end
  8142. currentdict /bn known {bn}if
  8143. †øÿ◊#ˇ ˇˇˇˇ#◊ 
  8144. d,Times
  8145. .+6-Macintosh Technical Notes /4/ ,
  8146. Courier
  8147.     °dONLNd(î*L    RectRgn(visRgn, inBounds);         {in case inBounds is > screen bounds}°dONLNdM'26*
  8148.   END;°dONLNdT;FΔ*V  WITH newPort^.portBits DO BEGIN       {baseAddr, rowBytes and bounds are in newPort}°dONLNd´EPã*
  8149.     bounds := inBounds;°dONLNd√OZî*
  8150. L    {rowBytes is size of row  It must be rounded up to even number of bytes}°dONLNdYdg*
  8151. C    rowBytes := ((inBounds.right - inBounds.left + 15) DIV 16) * 2;°dONLNdTmxD*<    {number of bytes in BitMap is rowBytes * number of rows}°dONLNdëwÇ≤*
  8152. R    {see note at end of Technical Note about using _NewHandle rather than _NewPtr}°dONLNd‰Ååè*
  8153. K    baseAddr := NewPtr(rowBytes * LONGINT(inBounds.bottom - inBounds.top));°dONLNd0ãñ6*
  8154.   END;°dONLNd7ï†ô*
  8155. M  IF MemError <> noErr THEN BEGIN    {see if we had enough room for the bits}°dONLNdÖü™Ü*
  8156.     SetPort(savePort);°dONLNdú©¥l*
  8157. D    ClosePort(newPort);              { dump the visRgn and clipRgn }°dONLNd·≥æ5*
  8158. 9    DisposPtr(Ptr(newPort));         { dump the GrafPort}°dONLNdΩ»«*
  8159. #    CreateOffscreenBitMap := false;°dONLNd?«“1*
  8160.   END°dONLNdE—‹T*
  8161.   ELSE BEGIN°dONLNdR€ÊÄ*
  8162. H    { since the bits are just memory, let's erase them before we start }°dONLNdõÂq*
  8163. E    EraseRect(inBounds);            {OpenPort did a SetPort(newPort)}°dONLNd·Ô˙§*
  8164.     newOffscreen := newPort;°dONLNd˛˘Ü*
  8165.     SetPort(savePort);°dONLNd¬*
  8166. "    CreateOffscreenBitMap := true;°dONLNd8
  8167. 6*
  8168.   END;°dONLNd?",*
  8169. END;
  8170. °dONLNdD-9∏*ZHere is the procedure to get rid of an off-screen bitmap created by the previous function:
  8171.     °dONLNdüEP5*9PROCEDURE DestroyOffscreenBitMap(oldOffscreen : GrafPtr);°dONLNdŸOZ1*
  8172. BEGIN°dONLNdflYd®*
  8173. P  ClosePort(oldOffscreen);                       { dump the visRgn and clipRgn }°dONLNd0cnb*
  8174. B  DisposPtr(oldOffscreen^.portBits.baseAddr);    { dump the bits }°dONLNdsmxb*
  8175. B  DisposPtr(Ptr(oldOffscreen));                  { dump the port }°dONLNd∂wÇ,*
  8176. END;
  8177. °dONLNdªçôº* Now that you know how to create °dONLNd€çºôÏ)§>and destroy an off-screen bitmap, let’s go through the motions°dONLNdö¶'(¬6<of using one.  First, let’s define a few things to make the °dONLNdVô'•m(¬E
  8178. _NewWindow°dONLNd`öm¶≈)F call a little clearer.
  8179.     °dONLNdx≤Ω1(Ÿ6CONST°dONLNd~º«Ü*
  8180.   kIsVisible   = true;°dONLNdïΔ—ã*
  8181.   kNoGoAway    = false;°dONLNd≠–€ê*
  8182.   kMakeFrontWindow = -1;°dONLNdΔ⁄Â*
  8183. 0  myString     = 'The EYE';  {string to display}
  8184. °dONLNd˜¸±*!Here’s the body of the test code:
  8185.     °dONLNd'*VAR°dONLNd
  8186. *
  8187. 1  offscreen : GrafPtr;    {our off-screen bitmap}°dONLNdO'*
  8188. 4  ovalRect  : Rect;       {used for example drawing}°dONLNdÑ&1*
  8189. /  myWBounds : Rect;       {for creating window}°dONLNd¥0;q*
  8190. E  OSRect    : Rect;       {portRect and bounds for off-screen bitmap}°dONLNd˙:Eê*
  8191.   myWindow  : WindowPtr;°dONLNdNY1*BEGIN°dONLNdXcb*
  8192. B  InitToolbox;                       {exercise left to the reader}°dONLNd\lwD*<  myWBounds := screenBits.bounds;    { size of main screen } ¶4¶ 
  8193. *(2) of 6(ªj!Drawing Into an Off-Screen BitmapˇR◊#ˇ ˇˇˇˇ#◊ 
  8194. d,Times
  8195. .+Z-Developer Support Center(-Û    June 1990 /X//,
  8196. Courier
  8197.     °dONLNd<(c(DZ;  InsetRect(myWBounds, 50,50);       { make it fit better }°dONLNd<'<2Ü*
  8198. B  myWindow := NewWindow(NIL, myWBounds, 'Test Window', kIsVisible,°dONLNd1<<÷*
  8199. R                        noGrowDocProc, WindowPtr(kMakeFrontWindow), kNoGoAway, 0);°dONLNd“E<Pü*G  IF NOT CreateOffscreenBitMap(offscreen,myWindow^.portRect) THEN BEGIN°dONLNdO<Zá*
  8200.     SysBeep(1);°dONLNd+Y<då*
  8201.     ExitToShell;°dONLNd<c<nZ*
  8202.   END;°dONLNdCw<Ç"*.  { Example drawing to our off-screen bitmap }°dONLNdrÅ<å•*
  8203.   SetPort(offscreen);°dONLNdàã<ñÃ*
  8204. P  OSRect := offscreen^.portRect;    { offscreen bitmap's local coordinate rect }°dONLNdŸï<†•*
  8205.   ovalRect := OSRect;°dONLNdÔü<™»*
  8206.   FillOval(ovalRect, black);°dONLNd ©<¥Õ*
  8207.   InsetRect(ovalRect, 1, 20);°dONLNd*≥<æ»*
  8208.   FillOval(ovalRect, white);°dONLNdGΩ<»Õ*
  8209.   InsetRect(ovalRect, 40, 1);°dONLNde«<“»*
  8210.   FillOval(ovalRect, black);°dONLNdÇ—<‹ñ*
  8211.   WITH ovalRect DO°dONLNdï€<Ê∏*
  8212. L    MoveTo((left+right-StringWidth(myString)) DIV 2, (top+bottom-12) DIV 2);°dONLNd‚Â<õ*
  8213.   TextMode(srcXor);°dONLNdˆÔ<˙Ø*
  8214.   DrawString(myString);°dONLNd<«*O  { copy from the off-screen bitmap to the on-screen window.  Note that in this°dONLNd^
  8215. <∏*
  8216. L  case the source and destination rects are the same size and both cover the°dONLNd´<"≥*
  8217. K  entire area.  These rects are allowed to be portions of the source and/or°dONLNd˜!<,—*
  8218. Q  destination and do not have to be the same size.  If they are not the same size°dONLNdI+<6*
  8219. -  then _CopyBits scales the image accordingly°dONLNdw5<@K*
  8220.   }°dONLNd{?<J†*
  8221.   SetPort(myWindow);°dONLNdêI<T;*
  8222. 3  CopyBits(offscreen^.portBits, myWindow^.portBits,°dONLNdƒS<^Ü*
  8223. B           offscreen^.portRect, myWindow^.portRect, srcCopy, NIL);°dONLNdg<rm*=  DestroyOffscreenBitMap(offscreen);    {remove the evidence}°dONLNdE{<Ü«*O  WHILE NOT Button DO;                  {give user a chance to see the results}°dONLNdïÖ<êP*
  8224. END.
  8225. °dONLNdöõ<ßh*MPW C°dONLNd†≥<ø=*:First, let’s look at a general purpose function to create °dONLNd⁄≥=ø(€[,an off-screen bitmap.  This function creates°dONLNd¿<ÃO(ËZthe °dONLNd øOÀá)GrafPort°dONLNd¿áÃs)8/ on the heap.  You could also create it on the °dONLNdB¿sÃ)Ï stack and pass the uninitialized°dONLNdcÃ<ÿ˛(ÙZ,structure to a function similar to this one.
  8226.     °dONLNdê‰<Ôê*DBoolean CreateOffscreenBitMap(GrafPtr *newOffscreen, Rect *inBounds)°dONLNd’Ó<˘A*
  8227. {°dONLNd◊¯<õ*
  8228.   GrafPtr savePort;°dONLNdÎ<
  8229. ñ*
  8230.   GrafPtr newPort;°dONLNd˛<!Æ*J  GetPort(&savePort);    /* need this to restore thePort after OpenPort */°dONLNdI*<5¬*N  newPort = (GrafPtr) NewPtr(sizeof(GrafPort));    /* allocate the grafPort */°dONLNdò4<?æ*
  8231.   if (MemError() != noErr)°dONLNd≥><I¬*
  8232. N    return false;                 /* failed to allocate the off-screen port */°dONLNdH<SP*
  8233.   /*°dONLNdR<]'*
  8234. /  the call to OpenPort does the following . . .°dONLNd8\<gÂ*
  8235. U    allocates space for visRgn (set to screenBits.bounds) and clipRgn (set wide open)°dONLNdéf<q◊*
  8236.     sets portBits to screenBits°dONLNdÆp<{˙*
  8237. &    sets portRect to screenBits.bounds ¶X¶/
  8238. *$!Drawing Into an Off-Screen Bitmap(ª3) of 6ˇÚ◊#ˇ ˇˇˇˇ#◊ 
  8239. d,Times
  8240. .+6-Macintosh Technical Notes /4/ ,
  8241. Courier
  8242.     °dONLNd(ü*    etc. (see IM I-163,164)°dONLNd'2Ô*
  8243. +    side effect: does a SetPort(&offScreen)°dONLNdH1<,*
  8244.   */°dONLNdM;F|*
  8245.   OpenPort(newPort);°dONLNdbEPS*
  8246. ?  /* make bitmap the size of the bounds that caller supplied */°dONLNd¢OZ∏*
  8247.    newPort->portRect = *inBounds;°dONLNd√Yd€*
  8248. '  newPort->portBits.bounds = *inBounds;°dONLNdÎcnº*
  8249. T  RectRgn(newPort->clipRgn, inBounds);    /* avoid wide-open clipRgn, to be safe  */°dONLNd@mxº*
  8250. T  RectRgn(newPort->visRgn, inBounds);     /* in case newBounds is > screen bounds */°dONLNdïÅå≠*Q  /* rowBytes is size of row, it must be rounded up to an even number of bytes */°dONLNdÁãñ∑*
  8251. S  newPort->portBits.rowBytes = ((inBounds->right - inBounds->left + 15) >> 4) << 1;°dONLNd;ü™N*>  /* number of bytes in BitMap is rowBytes * number of rows */°dONLNdz©¥¡*
  8252. U  /* see notes at end of Technical Note about using _NewHandle rather than _NewPtr */°dONLNd–≥æÆ*
  8253.   newPort->portBits.baseAddr =°dONLNdÔΩ»≤*
  8254. R           NewPtr(newPort->portBits.rowBytes * (long) (inBounds->bottom - inBounds°dONLNdAΩ≤»∑(‰–-°dONLNdB«“;(Ó6>top));°dONLNdJ—‹≤*
  8255. R  if (MemError()!=noErr) {   /* check to see if we had enough room for the bits */°dONLNdù€ÊÜ*
  8256.     SetPort(savePort);°dONLNd¥ÂN*
  8257. >    ClosePort(newPort);      /* dump the visRgn and clipRgn */°dONLNdÛÔ˙*
  8258. 4    DisposPtr((Ptr)newPort); /* dump the GrafPort */°dONLNd(˘0*
  8259. 8    return false;            /* tell caller we failed */°dONLNda1*
  8260.     }°dONLNdg
  8261. Ä*
  8262. H  /* since the bits are just memory, let's clear them before we start */°dONLNd∞"ô*
  8263. M  EraseRect(inBounds);     /* OpenPort did a SetPort(newPort) so we are ok */°dONLNd˛!,ö*
  8264.   *newOffscreen = newPort;°dONLNd+6|*
  8265.   SetPort(savePort);°dONLNd.5@D*
  8266. <  return true;               /* tell caller we succeeded! */°dONLNdk?J*
  8267. }
  8268. °dONLNdmUa∞*YHere is the function to get rid of an off-screen bitmap created by the previous function:
  8269.     °dONLNd«mx
  8270. *1void DestroyOffscreenBitMap(GrafPtr oldOffscreen)°dONLNd˘wÇ*
  8271. {°dONLNd˚Åå≤*
  8272. R  ClosePort(oldOffscreen);                       /* dump the visRgn and clipRgn */°dONLNdNãñl*
  8273. D  DisposPtr(oldOffscreen->portBits.baseAddr);    /* dump the bits */°dONLNdìï†l*
  8274. D  DisposPtr((Ptr)oldOffscreen);                  /* dump the port */°dONLNdÿü™*
  8275. }
  8276. °dONLNd⁄µ¡º* Now that you know how to create °dONLNd˙µº¡Ï)§>and destroy an off-screen bitmap, let’s go through the motions°dONLNd9¬Œ'(Í6<of using one.  First, let’s define a few things to make the °dONLNdu¡'Õm(ÍE
  8277. _NewWindow°dONLNd¬mŒ≈)F call a little clearer.
  8278.     °dONLNdó⁄Âã(6#define kIsVisible true°dONLNd؉Ôã*
  8279. #define kNoGoAway false°dONLNd«Ó˘ü*
  8280. #define kNoWindowStorage 0L°dONLNd„¯÷*
  8281. &#define kFrontWindow ((WindowPtr) -1L)
  8282. °dONLNd
  8283. ±*!Here’s the body of the test code:
  8284.     °dONLNd,&16*main()°dONLNd30;*
  8285. {°dONLNd5:E0*
  8286. 8  char* myString = "\pThe EYE";  /* string to display */°dONLNdnNYD*<  GrafPtr   offscreen;           /* our off-screen bitmap */°dONLNd´XcS*
  8287. ?  Rect      ovalRect;            /* used for example drawing */°dONLNdÎbm:*
  8288. :  Rect      myWBounds;           /* for creating window */°dONLNd    &lw£*
  8289. O  Rect      OSRect;              /* portRect and bounds for off-screen bitmap*/ ¶4¶ 
  8290. *(4) of 6(ªj!Drawing Into an Off-Screen Bitmapˇî◊#ˇ ˇˇˇˇ#◊ 
  8291. d,Times
  8292. .+Z-Developer Support Center(-Û    June 1990 /X//,
  8293. Courier
  8294.     °dONLNd<(•(DZ  WindowPtr myWindow;°dONLNd1<<r*>  InitToolbox();                 /* exercise for the reader */°dONLNdU;<Fr*
  8295. >  myWBounds = qd.screenBits.bounds;  /* size of main screen */°dONLNdîE<PY*
  8296. 9  InsetRect(&myWBounds, 50,50);  /* make it fit better */°dONLNdŒO<Z—*
  8297. Q  myWindow = NewWindow(kNoWindowStorage, &myWBounds, "\pTest Window", kIsVisible,°dONLNd Y<dÜ*
  8298. B                       noGrowDocProc, kFrontWindow, kNoGoAway, 0);°dONLNdcc<n|*
  8299. @  if (!CreateOffscreenBitMap(&offscreen, &myWindow->portRect)) {°dONLNd§m<xá*
  8300.     SysBeep(1);°dONLNd¥w<Çñ*
  8301.     ExitToShell();°dONLNd«Å<åU*
  8302.     }°dONLNdÕã<ñ'*
  8303. /  /* Example drawing to our off-screen bitmap*/°dONLNd˝ï<†•*
  8304.   SetPort(offscreen);°dONLNdü<™«*
  8305. O  OSRect = offscreen->portRect;  /* offscreen bitmap's local coordinate rect */°dONLNdc©<¥†*
  8306.   ovalRect = OSRect;°dONLNdx≥<æ‹*
  8307.    FillOval(&ovalRect, qd.black);°dONLNdôΩ<»“*
  8308.   InsetRect(&ovalRect, 1, 20);°dONLNd∏«<“‹*
  8309.    FillOval(&ovalRect, qd.white);°dONLNdŸ—<‹“*
  8310.   InsetRect(&ovalRect, 40, 1);°dONLNd¯€<Ê‹*
  8311.    FillOval(&ovalRect, qd.black);°dONLNdÂ<ü*
  8312. G  MoveTo((ovalRect.left + ovalRect.right - StringWidth(myString)) >> 1,°dONLNdaÔ<˙E*
  8313. 5         (ovalRect.top + ovalRect.bottom - 12) >> 1);°dONLNdó˘<õ*
  8314.   TextMode(srcXor);°dONLNd´<Ø*
  8315.   DrawString(myString);°dONLNd√<"Ã*P  /* copy from the off-screen bitmap to the on-screen window.  Note that in this°dONLNd!<,∏*
  8316. L  case the source and destination rects are the same size and both cover the°dONLNda+<6≥*
  8317. K  entire area.  These rects are allowed to be portions of the source and/or°dONLNd≠5<@—*
  8318. Q  destination and do not have to be the same size.  If they are not the same size°dONLNdˇ?<J"*
  8319. .  then _CopyBits scales the image accordingly.°dONLNd.I<TP*
  8320.   */°dONLNd3S<^†*
  8321.   SetPort(myWindow);°dONLNdH]<hO*
  8322. 7  CopyBits(&offscreen->portBits, &(*myWindow).portBits,°dONLNdÄg<rï*
  8323. E           &offscreen->portRect, &(*myWindow).portRect, srcCopy, 0L);°dONLNdΔ{<ܧ*H  DestroyOffscreenBitMap(offscreen);    /* dump the off-screen bitmap */°dONLNdÖ<ê§*
  8324. H  while (!Button());     /* give user a chance to see our work of art */°dONLNdXè<öA*
  8325. }
  8326. °dONLNdZ±<¿Ä*&Comments
  8327. °dONLNdcÕ<ŸÏ*%In the example code, the bits of the °dONLNdàÃÏÿ)∞BitMap°dONLNdéÕŸ~)* structure, which are °dONLNd§Õ~Ÿÿ)hpointed to by the °dONLNd∂Ãÿÿ)ZbaseAddr°dONLNdø⁄<ʨ(Zfield, are allocated by a °dONLNdŸŸ¨›)p_NewPtr°dONLNd‡⁄›Ê¶)1. call.  If your off-screen bitmap is close to °dONLNd⁄¶Ê)…the size of the screen,°dONLNd&Ê<Ú8(Z2then the amount of memory needed for the bits can °dONLNdXÊ8Ú)¸+be quite large (on the order of 20K for the°dONLNdÑÚ<˛≥(ZLMacintosh SE or 128K for a large screen).  This is quite a lot of memory to °dONLNd–Ú≥˛(—lock down in your°dONLNd‚˛<
  8328. ≈(&Zheap and it can easily lead to °dONLNd˛≈
  8329. )âDfragmentation if you intend to keep the off-screen bitmap around for°dONLNdF <î(3ZMany length of time.  One alternative that lessens this problem is to get the °dONLNdì îª(3≤    bits via °dONLNdú
  8330. ª)'
  8331. _NewHandle°dONLNd¶ )F so°dONLNd™<#§(?Zthe Memory Manager °dONLNdΩ§#)hFcan move them when necessary.  To implement this approach, you need to°dONLNd    $<0Ó(LZ"keep the handle separate from the °dONLNd    &#Ó/&)≤GrafPort°dONLNd    .$&0è)8 (for example, in a °dONLNd    B$è0)istructure that combines a°dONLNd    \0<<t(YZGrafPort°dONLNd    d1t=ñ)8 and a °dONLNd    k0ñ<¿)"Handle°dONLNd    q1¿=¸)*>).  When you want to use the off-screen bitmap you would then °dONLNd    Ø1¸=(Ylock°dONLNd    ¥><J-(fZ4the handle and put the dereferenced handle into the °dONLNd    Ë=-Ie)ÒbaseAddr°dONLNd    >eJh)8 °dONLNd    Ò>hJ)"field.  When you are not using the°dONLNd
  8332. J<V˛(rZ)off-screen bitmap you can then unlock it.°dONLNd
  8333. >b<ny*BThis example does not demonstrate one of the more typical uses of °dONLNd
  8334. Äbyn(äóoff-screen bitmaps, which is to°dONLNd
  8335. †n<z}(ñZBpreserve the contents of windows so that after a temporary window °dONLNd
  8336. ‚n}z(ñõor dialog box obscures part of ¶X¶/
  8337. (ªZ!Drawing Into an Off-Screen Bitmap(ª5) of 6ˇ◊#ˇ ˇˇˇˇ#◊ 
  8338. d,Times
  8339. .+6-Macintosh Technical Notes /4/
  8340. °dONLNd)`*
  8341. your windows °dONLNd
  8342. `)Ï)HQand is then dismissed, you can quickly handle the resulting update events without°dONLNd_)5(Q64recreating all of the intermediate drawing commands.°dONLNdîAMV*DMake sure you only restore the pixels within the content regions of °dONLNdÿAVMÏ(ityour own windows in case the°dONLNdıMYw(u6temporary window °dONLNdMwYÏ)_Jpartly obscures windows belonging to other applications or to the desktop.°dONLNdRYeù(Å6Another application could °dONLNdlYùeÏ)Ö=change the contents of its windows while they are behind your°dONLNd™eq†(ç6temporary window, so you °dONLNd√e†qÏ)àCcannot simply restore all the pixels that were behind the temporary°dONLNdq}¬(ô6"window because that would restore °dONLNd)q¬}Ï)™>the old contents of the other application’s windows.  Instead,°dONLNdh}â√(•6"you could keep keep an off-screen °dONLNdä}√âÏ)´8bitmap for each of your windows and then restore them by°dONLNd√âï€(±6]copying each bit map into the corresponding window’s ports when they get their update events.°dONLNd!°≠H*BAn alternate method is to make a single off-screen bitmap that is °dONLNdc°H≠Ï(…f as large as the temporary window°dONLNdÑ≠π(’66and a region that is the union of the content regions °dONLNd∫≠πÏ)ˇ(of your windows.  Before you display the°dONLNd„π≈(·66temporary window, copy the screen into the off-screen °dONLNdπ≈Ï(·<*bit map using the region as a mask.  After°dONLNdD≈—Ü(Ì6the temporary window °dONLNdY≈Ü—Ï)nJis dismissed, restore the obscured area by copying from the off-screen bit°dONLNd§—›\(˘6Bmap into a copy of the Window Manager port, and use the region as °dONLNdÊ—\›Ï(˘za mask.  If the region has the°dONLNdfiÍÃ(6'proper shape and location, it prevents ,
  8343. Courier°dONLNd,›ÃÈ )¥    _CopyBits°dONLNd5fi Íï)? from drawing outside of the °dONLNdRfiïÍÏ)äcontent regions of°dONLNde͈—(6"your windows.  See Technical Note °dONLNdáÍ—ˆÏ)π6#194, WMgrPortability for details about drawing across°dONLNdæˆH(6windows.°dONLNd«]*GIn some cases it can be just as fast and convenient to simply define a °dONLNd]Ï(6{picture (PICT) and then draw°dONLNd+&Ï(B6+it into your window when necessary.  There °dONLNdVÏ&Ï)‘6are cases, however, such as text rotation, where it is°dONLNdç&2±(N6advantageous to do the drawing °dONLNd¨&±2Ï)ôBoff the screen, manipulate the bit image, and then copy the result°dONLNdÔ2>    (Z61to the visible window (thus avoiding the dangers °dONLNd 2    >Ï)Ò0inherent in writing directly to the screen).  In°dONLNdQ>J˝(f62addition, this technique reduces flicker, because °dONLNdÉ>˝JÏ)Â1all of the drawing done off the screen appears on°dONLNdµJVo(r6the screen at once.°dONLNd…bnÀ*_It is also important to realize that, if you plan on using the pre-Color QuickDraw eight-color °dONLNd(bÀnÏ(äÈmodel,°dONLNd/nz‰(ñ6aan off-screen bitmap loses any color information and you do not see your colors on a system that °dONLNdên‰zÏ(ñis°dONLNdìzÜË(¢6*capable of displaying them.  In this case °dONLNdΩzËÜÏ)–0you should either use a PICT to save the drawing°dONLNdÓáìG(Ø6>information or check for the presence of Color QuickDraw and, °dONLNd    ,áGì¬(Øewhen it is present, use a °dONLNd    FܬíÏ){PixMap°dONLNd    Mî†=(º6instead °dONLNd    Uî=†V)%of a °dONLNd    ZìVüÄ)BitMap°dONLNd    `îĆ)* and the color toolbox calls (°dONLNd    ~î†e)íInside Macintosh°dONLNd    éîe†Ï)S, Volume V) instead of the°dONLNd    ©†¨ò(»6standard QuickDraw calls (°dONLNd    √†ò¨È)ÄInside Macintosh°dONLNd    ”†È¨$)Q , Volume I).°dONLNd    ‡∏ƒ
  8344. (‡64You may also want to refer to the OffScreen library °dONLNd
  8345. ∏
  8346. ƒÏ)ı)(DTS Sample Code #15) which provides both°dONLNd
  8347. >ƒ–π(Ï6Phigh- and low-level off-screen bitmap support for the 128K and later ROMs.  The °dONLNd
  8348. éƒπ–Ï(Ï◊    OffSample°dONLNd
  8349. ò–‹o(¯6Gapplication (DTS Sample Code #16) demonstrates the use of this library.°dONLNd
  8350. ‡ Ç*0Further Reference: +4+ °dONLNd
  8351. Û
  8352. *.+
  8353. •°dONLNd
  8354. ı
  8355. <ç)Inside Macintosh°dONLNd 
  8356. ç)Q, Volumes I & IV, QuickDraw°dONLNd !*%.(AH•°dONLNd #<%ç)Inside Macintosh°dONLNd 3ç%)Q, Volume V, Color QuickDraw°dONLNd O%*1.(MH•°dONLNd Q%<1
  8357. )(Technical Note M.IM.PrincipiaOffscreen —°dONLNd |1`=4+$ *Principia Off-Screen Graphics Environments°dONLNd ß=*I.(eH•°dONLNd ©=<IÈ)Technical Note M.TB.WMgrPort —°dONLNd  I`U≥+$  WMgrPortability°dONLNd €U*a.(}H•°dONLNd ›U<ao)9DTS Macintosh Sample Code #15, OffScreen & #16, OffSample ¶4¶
  8358. (ª66) of 6(ªj!Drawing Into an Off-Screen Bitmapˇº◊#ˇ ˇˇˇˇ#◊°d WORDS †å°d WORDR…†Ç 
  8359. /ZÅ#
  8360.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  8361. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  8362. .WIQkWIQk+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  8363. Ä({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  8364. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  8365.     l+&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  8366. BÄ(Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É°dWORD†ç
  8367. IR.°dONLNd{<éΔ(®ZOld Style Colors
  8368. °dONLNdç<úr*Imaging°dONLNdçêú˛(∏ÆM.IM.OldColors
  8369. °dONLNd(®<¥t(–Z Revised by:°dONLNd4®Ñ¥)HRich “I See Colors” Collyer°dONLNdP®¡¥˛(–fl August 1990°dONLNd\¥<¿q(‹Z Written by:°dONLNdh¥Ñ¿L)H'Rich “I See Colors” Collyer & Byron Han°dONLNdê¥æ¿˛(‹‹ October 1989°dONLNdùÃ<ÿ
  8370. (ÙZ*This Technical Note covers limitations of °dONLNd«Ã
  8371. ÿ˛)—0the original Macintosh color model (eight-color)°dONLNd¯ÿ<‰\(Zwhich °dONLNd˛ÿ\‰≠) Inside Macintosh°dONLNdÿ≠‰ì)Q,, Volume I-173, QuickDraw does not document.°dONLNd;‰<·( ZChanges since October 1989:°dONLNdV‰·∏)•/  Added definitions of the old-style constants. X°dONLNdÜ    <Û(1Z"QuickDraw has always been able to °dONLNd®    Û˛)∑4deal with color, just on a very limited basis.  Most°dONLNd›<!)(=Z0applications have not made use of this feature, °dONLNd
  8372. )!˛)Ì'since Color QuickDraw-based Macintoshes°dONLNd5!<-:(IZ5come with a better color model.  There are, however, °dONLNdj!:-˛)˛'a few nice features which come with the°dONLNdí-<9\(UZ>old style color model.  With the old style colors, it is easy °dONLNd–-\9˛(Uz to print color on an ImageWriter°dONLNdÒ9<E#(aZ0with a color ribbon.  Another advantage is that °dONLNd!9#E˛)Á,developers do not have to write special-case°dONLNdNE<Qâ(mZAcode depending upon whether or not a machine has Color QuickDraw.°dONLNdê]<ié*GNow that you are ready to convert to the old style colors, there are a °dONLNd◊]éi˛(Ö¨few things you should°dONLNdÌi<u‰(ëZYknow about which do not work with old style colors.  This Note covers the limitations of °dONLNdFi‰u˛(ëusing°dONLNdLu<Åõ(ùZLold style colors, as well as the best ways to work around these limitations.
  8373. °dONLNdôô<®à*' Limitations
  8374. °dONLNd•¥<¿‚*$The most obvious limitation is that °dONLNd…¥‚¿˛)¶<of only eight colors:  black, white, red, green, blue, cyan,°dONLNd¿<Ã"(ËZ.yellow, and magenta.  This limitation is only °dONLNd4¿"Ã˙)Ê(a problem if you want to produce a color°dONLNd\¿˙Ã˛)ÿ-°dONLNd]Ã<ÿı(ÙZ^intensive application; if this describes your application, then you need not read any further °dONLNdªÃıÿ˛(Ùin°dONLNdæÿ<‰k(Z
  8375. this Note.°dONLNd…<¸p*EThe next limitation is that off-screen buffers are not very useful.  °dONLNdp¸˛(éYou can draw into off-screen°dONLNd+¸<£($ZKbuffers, but there is no way to get the colors back from the buffer.  This °dONLNdv¸£˛($¡leads into the next°dONLNdä    <Æ(1Zlimitation, which is that ,
  8376. Courier°dONLNd§ÆÌ)r    _CopyBits°dONLNd≠    Ì∏)?+ cannot copy more than one color at a time.°dONLNdŸ"<.Ü(JZWhen you call °dONLNdÁ!Ü-≈)J    _CopyBits°dONLNd"≈.û)?+ from an off-screen buffer to your window, °dONLNd"û.˛)Ÿyou need to set the°dONLNd//<;(WZ/forecolor to the color you want to copy before °dONLNd^/;;)‹calling °dONLNdf.;:z)#    _CopyBits°dONLNdo/z;˛)? (i.e., to copy a red object,°dONLNdç<<HP(dZcall °dONLNdí;PG‹)_ForeColor(redColor)°dONLNd¶<‹H∑)å*).  Now when you copy the object, you can °dONLNd–<∑H˛)€
  8377. only copy one°dONLNdfiH<T
  8378. (pZ.color.  If you copy different colored objects °dONLNd H
  8379. T˛)—1at one time, then you have a problem.  The result°dONLNd>T<`÷(|ZZof a multicolored copy is that all objects copy in the same color, that of the foreground.°dONLNdôl<x0*5It is possible to work with an off-screen buffer and °dONLNdŒl0x˛)Ù.the old style colors, but it requires a lot of°dONLNd˝x<ÑV(†Zextra °dONLNd    xVÑ˛)Ywork.  Unless the objects are really complex, then it is probably easier to just draw the°dONLNd    ]Ñ<êfl(¨Z"objects directly into your window. ◊X◊
  8380. *@Old Style Colors(Ï1) of 3ˇ°¿Ù%%DSIDICT:_cv
  8381. currentdict /bu known {bu}if
  8382. userdict /_cv known not{userdict /_cv 30 dict put}if
  8383. _cv begin
  8384. /bdf{bind def}bind def
  8385. currentscreen/cs exch def/ca exch def/cf exch def
  8386. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  8387. /ss{//cf //ca //cs setscreen}bdf
  8388. /stg{ss setgray}bdf
  8389. /strgb{ss setrgbcolor}bdf
  8390. /stcmyk{ss cvcmyk}bdf
  8391. /min1{dup 0 eq{pop 1}if}bdf
  8392. end
  8393. currentdict /bn known {bn}if
  8394. †øÿ◊#ˇ ˇˇˇˇ#◊ 
  8395. IR,Times
  8396. .+6-Macintosh Technical Notes /4/˘
  8397. °dONLNd)*/One other limitation does exist.  Consider the °dONLNd/)⁄)ÿ-following code sample.  One would assume that°dONLNd])5√(Q6$this sample would work at all times.,
  8398. Courier
  8399.     °dONLNdÇALÅ*    SetPort (myPort);°dONLNdòKV≥*
  8400.     savedFG := myPort^.fgColor;°dONLNd∏U`5*
  8401. 9    ForeColor (redColor);            {or any other color}°dONLNdÚitÃ*$    {...drawing takes place here...}°dONLNd}àê*    ForeColor (savedFG);
  8402. °dONLNd0î†7*=Surprise.  It does not always work.  The saved value for the °dONLNdmì7üh(ºUfgColor°dONLNdtîh†ê)1
  8403.  field of °dONLNd~îꆢ)(the °dONLNdÇì¢ü⁄)GrafPort°dONLNdã°≠Œ(…6(is not a classic QuickDraw color if the °dONLNd≥†Œ¨)∂GrafPort°dONLNdª°≠C)8 is actually a °dONLNd †C¨Ç)=    CGrafPort°dONLNd”°Ç≠º)?.  If dealing °dONLNd·°º≠⁄):with a°dONLNdË≠πW(÷6    CGrafPort°dONLNdÒÆW∫q)?, the °dONLNd˜≠qπ¢)fgColor°dONLNd˛Æ¢∫$)1 field actually contains the °dONLNdÆ$∫⁄)Ç%foreground color’s entry in the color°dONLNdAª«ó(„6table, so the second call to °dONLNd^∫óΔ›)
  8404. _ForeColor°dONLNdhª›«R)F really messes things up.°dONLNdÇ‘‡¿(¸6$The proper way to set and reset the °dONLNd¶‘¿‡î)®*foreground color with classic QuickDraw’s °dONLNd–”îfl⁄)‘
  8405. _ForeColor°dONLNd€‡Ïj(6call is as follows:
  8406.     °dONLNdÔ¯Å*    SetPort (myPort);°dONLNd
  8407. ≥*
  8408.     savedFG := myPort^.fgColor;°dONLNd% 5*
  8409. 9    ForeColor (redColor);            {or any other color}°dONLNd_ +Ã*$    {...drawing takes place here...}°dONLNdÑ4?ä*J    myPort^.fgColor := savedFG;      {manually stuff the old fgColor back}°dONLNdœ>I£*
  8410. O    If (32BQD = TRUE) Then           {32BQD is a flag which is made and set by}°dONLNdHS≤*
  8411. R        PortChanged (myPort);        {the application; to set it, the application}°dONLNdrR]∑*
  8412. S                                     {needs to check _Gestalt for 32-Bit QuickDraw}
  8413. °dONLNdΔiu≈*&This Note also applies to the routine °dONLNdÏh≈t )≠
  8414. _BackColor°dONLNdˆi u)F.
  8415. °dONLNd¯çúj(∏6
  8416. What Works
  8417. °dONLNd®¥Q* The easiest °dONLNd®Q¥⁄)9Lway to work with these limited colors is to use pictures.  When you draw the°dONLNd\¥¿≠(‹6Oimages, you should draw into a picture.  Then when you want to draw the images °dONLNd´¥≠¿⁄(‹À    into your°dONLNdµ¡Õ¢(È6window or to a printer, call °dONLNd“¿¢È)ä _DrawPicture°dONLNdfi¡ˆÕπ)T).  Pictures work well with the old style °dONLNd¡πÕ⁄)√colors,°dONLNdÕŸå(ı6Land you don’t need to worry about making sure that the forecolor is current °dONLNd[ÕåŸ⁄(ı™
  8418. when you draw°dONLNdiŸÂq(6into your window.°dONLNd{Ò˝H*    Once you °dONLNdÑÒH˝⁄)0Uhave the picture, you can use it to draw into the screen or to the printer port.  You°dONLNd⁄˛
  8419. A(&6    can also °dONLNd„˛A
  8420. d))set the °dONLNdνd    ∏)# WindowRecord°dONLNd˜˛∏
  8421. ¡)Ts °dONLNd˘˝¡    )        windowPic°dONLNd˛
  8422. H)? to equal your °dONLNd˝H    £)H
  8423. PictureHandle°dONLNd˛£
  8424. ⁄)[  so updates°dONLNd*
  8425.  (26"are handled by the Window Manager.
  8426. °dONLNdM.=$*'#What Do Those Constants Mean Anyway
  8427. °dONLNdqIUÈ*,Each of the constants contains nine bits of °dONLNdùIÈU⁄)—0information, and each bit has a special meaning.°dONLNdœUaM(}6DFigure 1 illustrates the meaning of each of the bits, while Table 1 °dONLNdUMa⁄(}kshows how each of the color°dONLNd/amΔ(â6(constants fills in the appropriate bits. ◊4◊˘
  8428. *c2) of 3(Ï¥Old Style ColorsˇF◊#ˇ ˇˇˇˇ#◊ 
  8429. IR,Times
  8430. .+Z-Developer Support Center(-Ë August 1990 /X/†09†Ç
  8431. <√Ã≤òS,„S,„<√Ã≤Áˇ˛Ç ¸p¸¯p 0Ä ÄÄà`HÊsÄ(  Ñí$Ç¯H` Ñí#à Ñí Ç  Ñí$Ç ¸@ Ñ‚ ÑÄ H x‡¯ 0Áˇ˛˝@    @  ˝@    @  ˝@    @  ˝@    @  ˝@    @  ˝@    @  ˝@    @  ˝@    @  ˝    @  ˝    @  $«    @  %$Ä    @  $‰Ä    @  %$Ä    @  %$Ä    @  ‰Ä    @  ˛˛    @  ˛˚    @  ˜    @  ˜    @  ˜    @  ˛@@    @  ˛¿@    @  ˛LsÊ    @  ˛RîíI    @  ˛NóíG    @  ˛RîI    @  ˛RîíI    @  ˛Ns'    @  ¸˝    @  ¸`˙   @  Ù   @  Ù   @  ˚ f˝   @  ˚ "˝   @  ˚F"2   @  ˚I"J   @  ˙è"IP   @  ˙à"IP   @  ˙â"H†   @  ˙Ü"0†¸
  8432.   @  Ò
  8433.   @  Ò
  8434.   @  Ò
  8435.   @  Ò
  8436.   @  Ò
  8437.   @  ˜0@  @  ˜ê@  @  ˜ëåH  @  ˜RP  @  ˜ë–`  @  ˜íP`  @  ˜íRP  @  ˜ÃH  @  Ó
  8438.  @  Ó
  8439.  @  Ó
  8440.  @  Ó
  8441.  @  Û  @  ÛÄ  @  Ûò‡ @  Û•  @  Û=  @  Û
  8442. !  @  Û    %  @  Ûò‡ @  Ó
  8443.  @   Î@   Î@   Î@  Ò¸@  ÒÄ˝@  Ò
  8444. c@  Ò
  8445. îí@  Ò
  8446.     ê˜í@  Ò
  8447. êÑ@  Ò
  8448. êîí@  Ò
  8449. c@   Î@  Ë  Ë  Ë  Ë  
  8450. ÌyIJ  
  8451. ÌDIJ  
  8452. Ì    Dâ0  
  8453. Ì    xâH  
  8454. Ì    Dâx  
  8455. Ì    Dâ@  
  8456. Ì    DâH  
  8457. Ì    xá0  Ë  Ë  Â Â Â Â  Ù@ı  ˙¸    áò ` $˛ ˙¸    ÑH Ä"$˛ ˙âã1ÅHΔ$ù¿G3òé ˙äLJAâ)(HÄDë$I ˙S»3¡HË0ÚHÄDë<‚I ˙R
  8458. I(0HÄÑë I ˙"HJ@ÑI)(HÄÑë$I ˙!à1ÄáàÊ$àÑÑêòâ 
  8459. Ù@¸˘     Ó˘ „„„„„„ÒÄı@˜0@ à3 ˜êê@ D ˜ìv1ëåHí9ú¿ Ó˜TòIIRPí™$â D˜TêI9ë–a‰í™$âÁíD˜4êIIíP`íD$âD˜4êIIíRPíD$â D ˜I9ÃH D$Ñ¿ D  Òĸ ˚@Î@˙†É
  8460. IR
  8461. °dONLNdˇˇ(·ıFigure 1–Bit Definitions
  8462. °dONLNdˇˇ(πblack°dONLNdˇˇ),white°dONLNdˇˇ)4red°dONLNdˇˇ)'green°dONLNdˇˇ)/blue°dONLNdˇˇ)-cyan°dONLNdˇˇ)$magenta°dONLNdˇˇ)0yellow°dONLNdˇˇ(º(33)°dONLNdˇˇ)-(30)°dONLNdˇˇ)*(209)°dONLNdˇˇ)-(329)°dONLNdˇˇ)-(389)°dONLNdˇˇ)-(269)°dONLNdˇˇ)-(149)°dONLNdˇˇ)'(89) |°dONLNdˇˇ(~Cyan°dONLNdˇˇ)E0°dONLNdˇˇ)-0°dONLNdˇˇ)-0°dONLNdˇˇ)-1°dONLNdˇˇ)-1°dONLNdˇˇ)(1°dONLNdˇˇ)20°dONLNdˇˇ)0°dONLNdˇˇ('~Magenta°dONLNdˇˇ)E0°dONLNdˇˇ)-0°dONLNdˇˇ)-1°dONLNdˇˇ)-0°dONLNdˇˇ)-1°dONLNdˇˇ)(0°dONLNdˇˇ)21°dONLNdˇˇ)0°dONLNdˇˇ(2~Yellow°dONLNdˇˇ)E0°dONLNdˇˇ)-0°dONLNdˇˇ)-1°dONLNdˇˇ)-1°dONLNdˇˇ)-0°dONLNdˇˇ)(0°dONLNdˇˇ)20°dONLNdˇˇ)1°dONLNdˇˇ(=~Black°dONLNdˇˇ)E1°dONLNdˇˇ)-0°dONLNdˇˇ)-0°dONLNdˇˇ)-0°dONLNdˇˇ)-0°dONLNdˇˇ)(0°dONLNdˇˇ)20°dONLNdˇˇ)0°dONLNdˇˇ(H~Red°dONLNdˇˇ)E0°dONLNdˇˇ)-1°dONLNdˇˇ)-1°dONLNdˇˇ)-0°dONLNdˇˇ)-0°dONLNdˇˇ)(0°dONLNdˇˇ)21°dONLNdˇˇ)1°dONLNdˇˇ(S~Green°dONLNdˇˇ)E0°dONLNdˇˇ)-1°dONLNdˇˇ)-0°dONLNdˇˇ)-1°dONLNdˇˇ)-0°dONLNdˇˇ)(1°dONLNdˇˇ)20°dONLNdˇˇ)1°dONLNdˇˇ(^~Blue°dONLNdˇˇ)E0°dONLNdˇˇ)-1°dONLNdˇˇ)-0°dONLNdˇˇ)-0°dONLNdˇˇ)-1°dONLNdˇˇ)(1°dONLNdˇˇ)21°dONLNdˇˇ)0°dONLNdˇˇ(i~Inverse°dONLNdˇˇ)E0°dONLNdˇˇ)-1°dONLNdˇˇ)-0°dONLNdˇˇ)-0°dONLNdˇˇ)-0°dONLNdˇˇ)(0°dONLNdˇˇ)20°dONLNdˇˇ)0°dONLNdˇˇ(t~Normal°dONLNdˇˇ)E1°dONLNdˇˇ)-0°dONLNdˇˇ)-1°dONLNdˇˇ)-1°dONLNdˇˇ)-1°dONLNdˇˇ)(1°dONLNdˇˇ)21°dONLNdˇˇ)1 v|v
  8463. °dONLNdˇˇ(åÂTable 1–Color-Bit Correlation°dONLNdˇˇ(ºZFurther Reference: øXø°dONLNdˇˇ+
  8464. •°dONLNdˇˇ)Inside Macintosh°dONLNdˇˇ)Q, Volume I-173, QuickDraw°dONLNdˇˇ(’l•°dONLNdˇˇ)Technical Note M.IM.Copybits —°dONLNdˇˇ+$ Of Time and Space and _CopyBits ◊X◊
  8465. (ÏZOld Style Colors(Ï3) of 3ˇj◊#ˇ ˇˇˇˇ#◊†Ç 
  8466. /ZÅ#
  8467.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  8468. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  8469. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  8470. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  8471. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  8472.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  8473. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  8474. IR.°dONLNdz<çΔ(ßZ*Things You Wanted to Know About _PackBits*°dONLNd,årüA+6*But Were Afraid to Ask
  8475. °dONLNdDû<≠r(…ZImaging°dONLNdLûõ≠˛(…π
  8476. M.IM.PackBits
  8477. °dONLNdZπ<≈t(·Z Revised by:°dONLNdfπÑ≈])H,Guillermo Ortiz, Jon Zap, and Forrest Tanaka°dONLNdìπæ≈˛(·‹ January 1992°dONLNd†≈<—q(ÌZ Written by:°dONLNd¨≈Ñ—À)H
  8478. Cameron Birse°dONLNd∫≈±—˛(Ìœ
  8479. November 1987°dONLNd»fi<Ír(Z?This Technical Note describes the format of data packed by the °dONLNdfirÍø(êToolbox utility ,
  8480. Courier°dONLNd›øÈ˛)M    _PackBits°dONLNd!Î<˜’(Zand documents a change to the °dONLNd?Í’ˆ
  8481. )ôsrcBytes°dONLNdGÎ
  8482. ˜â)8 limit and possible worst °dONLNdaÎâ˜˛)|case. Although you can°dONLNdx¯<⁄( Zsimply unpack this data using °dONLNdñ˜⁄')û _UnPackBits°dONLNd°¯'˛)M), Apple provides this information for the°dONLNdÀ<A(-Z6terminally curious and for those manipulating MacPaint
  8483.     °dONLNdAH(*_®
  8484. °dONLNdHÏ+! documents or PICT files by hand.°dONLNd%<t(9Z    Warning: °dONLNd.tH)8-This format information is subject to change.°dONLNd\<)Ô(EZChanges since November 1990:°dONLNdxÔ):)≥ A warning has °dONLNdá:)˙)K'been added about the handling of a flag°dONLNdÆ˙)˛)¿-°dONLNdØ)<5º(QZcounter byte value of -128. `X`
  8485. °dONLNdÀZ<i“*4Length Doesn’t Matter
  8486. °dONLNd·v<Ç]*Inside °dONLNdËv]Çé)!    Macintosh°dONLNdÒvéÇô)16, Volume I-470, describes the Pascal interface to the °dONLNd'uôÅÿ(û∑    _PackBits°dONLNd0vÿDz)? trap as°dONLNd9Ç<éc(™Zfollows:
  8487.     °dONLNdBö<•|*@    PROCEDURE PackBits(VAR srcPtr,dstPtr:Ptr; srcBytes:INTEGER);
  8488. °dONLNdɱ<Ωò*The accompanying °dONLNdî±òΩ‡)\text states that °dONLNd•∞‡º)HsrcBytes°dONLNd≠±Ω˛)8., the length of your uncompressed data, should°dONLNd‹æ< Ù(ÊZ)not be greater than 127, and that in the °dONLNdæÙ ∑)∏'worst case, the compressed data can be °dONLNd,Ω∑…˛)√
  8489. srcBytes +°dONLNd7 <÷C(ÛZ1°dONLNd8ÀC◊Ó)U. To pack more than 127 bytes, you had to break the data up into 127-byte groups and °dONLNdçÀÓ◊˛(Û call°dONLNdí◊<„{(Z    _PackBits°dONLNdõÿ{‰¸)? on each group. Beginning °dONLNdµÿ¸‰˛)Å5with system software version 6.0.2, this limit of 127°dONLNdΉ<Î( Z"bytes is no longer valid. The new °dONLNd
  8490. ‰Î˛)Ø4limit is 32,767 bytes, which is the maximum positive°dONLNdBÒ<˝}(Z number that °dONLNdN}¸µ)AsrcBytes°dONLNdVÒµ˝—)8 can °dONLNd[Ò—˝˛)7hold. The worst case can be determined according to the°dONLNdì˝<    ï(%Zfollowing formula:
  8491.     °dONLNd¶< ˇ*'    (srcBytes + (srcBytes+126) DIV 127)
  8492. °dONLNdŒ+<7,*1which is comparable to what you would get if you °dONLNdˇ+,7˛)*broke up the data into 127-byte groups and°dONLNd*7<C (_Z,picked up an additional byte for each group.
  8493. °dONLNdW[<jW*'$Mommy, How Do They Make Packed Bits?
  8494. °dONLNd|v<Ç›*VThe first byte is a flag-counter byte that specifies whether or not the the following °dONLNd“v›Ç˛(û˚data is°dONLNd⁄Ç<é¥(™Zpacked, and the number °dONLNdÒÇ¥é˛)xDof bytes involved. If this first byte is a negative number, then the°dONLNd6é<ö (∂Z,following data is packed. In this case, the °dONLNdbé ö˛)œ.number is the two’s complement of a zero-based°dONLNdëö<¶z(¬Z
  8495. count of the °dONLNdûöz¶˛)>Knumber of times the data byte repeats when expanded. There is one data byte ◊X◊
  8496. (ÏZ)Things You Wanted to Know About _PackBits(Ï1) of 4ˇ°¿Ù%%DSIDICT:_cv
  8497. currentdict /bu known {bu}if
  8498. userdict /_cv known not{userdict /_cv 30 dict put}if
  8499. _cv begin
  8500. /bdf{bind def}bind def
  8501. currentscreen/cs exch def/ca exch def/cf exch def
  8502. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  8503. /ss{//cf //ca //cs setscreen}bdf
  8504. /stg{ss setgray}bdf
  8505. /strgb{ss setrgbcolor}bdf
  8506. /stcmyk{ss cvcmyk}bdf
  8507. /min1{dup 0 eq{pop 1}if}bdf
  8508. end
  8509. currentdict /bn known {bn}if
  8510. †ø$◊#ˇ ˇˇˇˇ#◊ 
  8511. IR,Times
  8512. .+6-Macintosh Technical Notes /4/˘
  8513. °dONLNd)Ò*.following this first byte in packed data. The °dONLNd.Ò)⁄)Ÿ1byte after the data byte is the next flag-counter°dONLNd`)50(Q6byte.°dONLNdfAM*8If the flag-counter byte is a positive number, then the °dONLNdûAM⁄)˝)following data is unpacked. In this case,°dONLNd»MYò(u6Qthe number is a zero-based count of the number of incompressible data bytes that °dONLNdMòY⁄(u∂
  8514. follow. There°dONLNd'Yeâ(Å6Pare (flag-counter+1) data bytes following the flag-counter byte. The byte after °dONLNdwYâe⁄(Åßthe last data byte°dONLNdäeqü(ç6is the next flag-counter byte.°dONLNd©}âø*#Note that there is no way to know, °dONLNdÃ}øâ⁄)ß:given a pointer to the start of packed data, when you have°dONLNdâï¨(±6reached the end of the packed °dONLNd%â¨ï⁄)î;data. This is why you need to know either the length of the°dONLNdañ¢(æ64packed or unpacked data before you start unpacking. ,
  8515. Courier°dONLNdïï°a)¸ _UnPackBits°dONLNd†ña¢æ)M requires the length °dONLNdµñæ¢⁄)]of the°dONLNdº¢Æ_( 6unpacked data.°dONLNdÀª«L*Warning:°dONLNd‘∫`Δü)H    _PackBits°dONLNd›ªü«)? never generates the °dONLNdÚª«∂)h"value -128 ($80) as a flag-counter°dONLNd«`”3(Ô~'byte, but a few PackBits-like routines °dONLNd<«3”∂)”that are built into some°dONLNdU‘`‡Æ(¸~applications do. °dONLNdf”Æfl˚)N _UnpackBits°dONLNdq‘˚‡∂)M' handles this situation by skipping any°dONLNdô‡`ϵ(~flag-counter byte °dONLNd´‡µÏ∂)U5with this value and interpreting the next byte as the°dONLNd·Ï`¯i(~3next flag-counter byte. If you’re writing your own °dONLNdÏi¯∂(áUnpackBits-like°dONLNd$¯`z( ~=routine, make sure it handles this situation in the same way.°dONLNdb≤(86Consider the following example:°dONLNdÇ(4a*Unpacked data:
  8516.     °dONLNdë@Kè*K    AA AA AA 80 00 2A AA AA AA AA 80 00 2A 22 AA AA AA AA AA AA AA AA AA AA
  8517. °dONLNd›WcÉ*After being packed by °dONLNdÛVÉb¬)k    _PackBits°dONLNd¸W¬c≈)?:
  8518.     °dONLNd˛ozq(ñ6E    FE AA                    ; (-(-2)+1) = 3 bytes of the pattern $AA°dONLNdDyÑS*
  8519. ?    02 80 00 2A              ; (2)+1 = 3 bytes of discrete data°dONLNdÑÉéq*
  8520. E    FD AA                    ; (-(-3)+1) = 4 bytes of the pattern $AA°dONLNd çòS*
  8521. ?    03 80 00 2A 22           ; (3)+1 = 4 bytes of discrete data°dONLNd
  8522. ó¢v*
  8523. F    F7 AA                    ; (-(-9)+1) = 10 bytes of the pattern $AA
  8524. °dONLNdQ≠π7*           or
  8525.     °dONLNd[≈–*0    FE AA 02 80 00 2A FD AA 03 80 00 2A 22 F7 AA°dONLNdåœ⁄Ù*
  8526. ,    *     *           *     *              *
  8527. °dONLNdπÊÚI*
  8528. The bytes °dONLNd√ÊIÚj)1=with the asterisk (*) under them are the flag-counter bytes. °dONLNdÂjÒ©(à    _PackBits°dONLNd    Ê©Ú⁄)?
  8529.  packs the°dONLNdÚ˛}(6data only when there °dONLNd)Ú}˛⁄)eIare three or more consecutive bytes with the same data; otherwise it just°dONLNds˛
  8530. (&68copies the data byte for byte (and adds the count byte).°dONLNd¨#7*Note:°dONLNd≤<#Ò)$#The data associated with some PICT °dONLNd’Ò#H)µopcodes, $0098 (°dONLNdÂH"ú)W PackBitsRect°dONLNdÒú#∂)T) and°dONLNd˜$<0a(LZ$0099 °dONLNd˝$a0e)%(°dONLNd˛#e/≤) PackBitsRgn°dONLNd    $≤0Ï)M ), contain °dONLNd#Ï/):PixData°dONLNd$0∂)1 which is basically made of°dONLNd70<<{(YZ    _PackBits°dONLNd@1{=ÿ)? data. It should be °dONLNdT1ÿ=Ö)]#noted, though, that the format for °dONLNdw0Ö<∂)≠PixData°dONLNd><Jn(fZ includes a °dONLNdä=nI≠)2    byteCount°dONLNdì>≠J∞)?: or length in addition to the data described in this Note.°dONLNdŒVb_(~6DFor example, the following is the result of decoding a sample PICT2:
  8531.     °dONLNd    nyÅ*data 'PICT' (25534) {°dONLNd    )xÉl*
  8532. D    0936 0000 0000 0007 001E                /* pic size, picFrame */°dONLNd    nÇçl*
  8533. D    0011 02FF                               /* pict2              */°dONLNd    ≥åól*
  8534. D    0C00                                    /* header             */°dONLNd    ¯ñ°l*
  8535. D         FFFF FFFF 0000 0000 0000 0000 001E 0000 0007 0000 0000 0000°dONLNd
  8536. =†´l*
  8537. D    001E                                    /* def hilite         */ ◊4◊˘
  8538. *%2) of 4(Ï;)Things You Wanted to Know About _PackBitsˇfi◊#ˇ ˇˇˇˇ#◊ 
  8539. IR,Times
  8540. .+Z-/Developer Support Center                       (-Á January 1992 /X/,
  8541. Courier
  8542.     °dONLNd<(ê(DZD    0001                                    /* clipRgn            */°dONLNdE'<2·*
  8543. !         000A 0000 0000 0007 001E°dONLNdg1<<ê*
  8544. D    0098                                    /* PackBitsRect       */°dONLNd¨;<Fê*
  8545. D         801E                               /* rowbytes of 30     */°dONLNdÒE<Pê*
  8546. D         0000 0000 0007 001E                /* Bounds             */°dONLNd6O<Zê*
  8547. D         0000                               /* packType           */°dONLNd{Y<dê*
  8548. D         0000                               /* version            */°dONLNd¿c<nê*
  8549. D         0000 0000                          /* packSize           */°dONLNdm<xê*
  8550. D         0048 0000                          /* hRes               */°dONLNdJw<Çê*
  8551. D         0048 0000                          /* vRes               */°dONLNdèÅ<åê*
  8552. D         0000                               /* pixelType          */°dONLNd‘ã<ñê*
  8553. D         0008                               /* pixelSize          */°dONLNdï<†ê*
  8554. D         0001                               /* cmpCount           */°dONLNd^ü<™ê*
  8555. D         0008                               /* cmpSize            */°dONLNd£©<¥ê*
  8556. D         0000 0000                          /* planeBytes         */°dONLNdË≥<æê*
  8557. D         0000 1F10                          /* pmTable            */°dONLNd-Ω<»ê*
  8558. D         0000 0000                          /* pmReserved         */°dONLNdr«<“Ø*
  8559.         /*color table*/°dONLNdä—<‹ê*
  8560. D              0000 4CBC                     /* ctSeed             */°dONLNdœ€<Êê*
  8561. D              8000                          /* ctFlags            */°dONLNdÂ<ê*
  8562. D              00FF                          /* ctSize             */°dONLNdYÔ<˙˙*
  8563. &                   0000 FFFF FFFF FFFF°dONLNdĢ<ê*
  8564. D                   ...                 /* 254 ColorSpec's omitted */°dONLNd≈<˙*
  8565. &                   0000 0000 0000 0000°dONLNdÏ
  8566. <ê*
  8567. D         0000 0000 0007 001E                /* srcRect            */°dONLNd1<"ê*
  8568. D         0000 0000 0007 001E                /* dstRect            */°dONLNdv!<,ê*
  8569. D         0000                               /* srcCopy            */°dONLNdª5<@m*=         /* Now we have the scan line data packed as follows:°dONLNd˘?<Jï*
  8570. E            [bytecount for current scan line] [data as defined above]°dONLNd?I<T§*
  8571. H            If rowBytes is > 250 then byteCount is a word else is a byte°dONLNdàS<^'*
  8572. /            (in this case, byteCount is a byte)°dONLNd∏]<hc*
  8573. ;            note that each unpacked row adds to 30 rowBytes°dONLNdÙg<rs*
  8574.          */°dONLNd{<Ür*>         /* line 1, byte count is 2 (best case for a row)   */°dONLNd?Ö<ês*
  8575.          02°dONLNdKè<ör*
  8576. >            E3 FF                /* -(-29) + 1 = 30 FF's    */°dONLNdäô<§r*
  8577. >         /* line 2, byte count is 19 (0x13)                 */°dONLNd…£<Æs*
  8578.          13°dONLNd’≠<∏r*
  8579. >            01 FF 23             /* 1+1 data bytes          */°dONLNd    ∑<¬r*
  8580. >            FE 00                /* -(-2)+1 0's             */°dONLNd    S¡<Ãr*
  8581. >            FC 23                /* -(-4)+1 0x23's          */°dONLNd    íÀ<÷r*
  8582. >            FE 00                /* 3 0's                   */°dONLNd    —’<‡r*
  8583. >            FC 23                /* 5 0x23's                */°dONLNd
  8584. fl<Ír*
  8585. >            FE 00                /* 3 0's                   */°dONLNd
  8586. OÈ<Ùr*
  8587. >            FC 23                /* 5 0x23's                */°dONLNd
  8588. éÛ<˛r*
  8589. >            FE 00                /* 3 0's                   */°dONLNd
  8590. Õ˝<r*
  8591. >            00 FF                /* 1 data byte             */°dONLNd <r*
  8592. >         /* line 3, byte count is 28                        */°dONLNd K<s*
  8593.          1C°dONLNd W<&r*
  8594. >            02 FF 00 23          /* 3 data bytes            */°dONLNd ñ%<0r*
  8595. >            FE 00                /* 3 0's                   */°dONLNd ’/<:r*
  8596. >            FE 23                /* 3 0x23's                */°dONLNd 9<Dr*
  8597. >            01 00 23             /* 2 data bytes            */°dONLNd SC<Nr*
  8598. >            FE 00                /* 3 0's                   */°dONLNd íM<Xr*
  8599. >            FE 23                /* 3 0x23's                */°dONLNd —W<br*
  8600. >            01 00 23             /* 2 data bytes            */°dONLNd
  8601. a<lr*
  8602. >            FE 00                /* 3 0's                   */°dONLNd
  8603. Ok<vr*
  8604. >            FE 23                /* 3 0x23's                */°dONLNd
  8605. éu<Är*
  8606. >            04 00 23 00 00 FF    /* 5 data bytes            */°dONLNd
  8607. Õ<är*
  8608. >         /* line 4, byte count is 31 (worst case for a row) */°dONLNd â<îs*
  8609.          1F°dONLNdì<ûr*
  8610. >            03 FF 00 00 23       /* 4 data bytes            */°dONLNdWù<®r*
  8611. >            FE 00                /* 3 0's                   */ ◊X◊
  8612. *()Things You Wanted to Know About _PackBits(Ï3) of 4ˇ◊#ˇ ˇˇˇˇ#◊ 
  8613. IR,Times
  8614. .+6-Macintosh Technical Notes /4/˘,
  8615. Courier
  8616.     °dONLNd(N*>            00 23                /* 1 data byte             */°dONLNd?'2N*
  8617. >            FE 00                /* 3 0's                   */°dONLNd~1<N*
  8618. >            00 23                /* 1 data byte             */°dONLNdΩ;FN*
  8619. >            FE 00                /* 3 0's                   */°dONLNd¸EPN*
  8620. >            00 23                /* 1 data byte             */°dONLNd;OZN*
  8621. >            FE 00                /* 3 0's                   */°dONLNdzYdN*
  8622. >            00 23                /* 1 data byte             */°dONLNdπcnN*
  8623. >            FE 00                /* 3 0's                   */°dONLNd¯mxN*
  8624. >            00 23                /* 1 data byte             */°dONLNd7wÇN*
  8625. >            FE 00                /* 3 0's                   */°dONLNdvÅåN*
  8626. >            02 23 00 FF          /* 3 data bytes            */°dONLNdµãñN*
  8627. >         /* line 5, byte count is 28                        */°dONLNdÙï†O*
  8628.          1C°dONLNdü™N*
  8629. >            01 FF 00             /* 2 data bytes            */°dONLNd?©¥N*
  8630. >            FE 23                /* 3 0x23's                */°dONLNd~≥æN*
  8631. >            01 00 23             /* 2 data bytes            */°dONLNdΩΩ»N*
  8632. >            FE 00                /* 3 0's                   */°dONLNd¸«“N*
  8633. >            FE 23                /* 3 0x23's                */°dONLNd;—‹N*
  8634. >            01 00 23             /* 2 data bytes            */°dONLNdz€ÊN*
  8635. >            FE 00                /* 3 0's                   */°dONLNdπÂN*
  8636. >            FE 23                /* 3 0x23's                */°dONLNd¯Ô˙N*
  8637. >            01 00 23             /* 2 data bytes            */°dONLNd7˘N*
  8638. >            FE 00                /* 3 0's                   */°dONLNdvN*
  8639. >            FE 23                /* 3 0x23's                */°dONLNdµ
  8640. N*
  8641. >            00 FF                /* 1 data byte             */°dONLNdÙ"N*
  8642. >         /* line 6, byte count is 18                        */°dONLNd3!,O*
  8643.          12°dONLNd?+6N*
  8644. >            00 FF                /* 1 data byte             */°dONLNd~5@N*
  8645. >            FC 23                /* 5 0x23's                */°dONLNdΩ?JN*
  8646. >            FE 00                /* 3 0's                   */°dONLNd¸ITN*
  8647. >            FC 23                /* 5 0x23's                */°dONLNd;S^N*
  8648. >            FE 00                /* 3 0's                   */°dONLNdz]hN*
  8649. >            FC 23                /* 5 0x23's                */°dONLNdπgrN*
  8650. >            FE 00                /* 3 0's                   */°dONLNd¯q|N*
  8651. >            FD 23                /* 4 0x23's                */°dONLNd7{ÜN*
  8652. >            00 FF                /* 1 data byte             */°dONLNdvÖêN*
  8653. >         /* line 7, byte count is 2 (best case for a row)   */°dONLNdµèöO*
  8654.          02°dONLNd¡ô§N*
  8655. >            E3 FF                /* 30 0xFF's               */°dONLNd    £ÆN*
  8656. >         00  /* pad so next command starts at word boundary */°dONLNd    ?∑¬N*>    00FF                         /*end of pic               */°dONLNd    ~¡Ã"*
  8657. };
  8658. °dONLNd    ÅÔ˚Ç*/Further Reference: 4˘°dONLNd    î¸*.+
  8659. •°dONLNd    ñ¸<ç)Inside Macintosh°dONLNd    ¶¸çB)Q%, Volume I-465, The Toolbox Utilities°dONLNd    Ã*.(0H•°dONLNd    Œ<ç)Inside Macintosh°dONLNd    fiç/)Q, Volume V-39, Color QuickDraw°dONLNd    ˝* .(<H•°dONLNd    ˇ< Ù)!Technical Note M.PT.MacPaintDoc —°dONLNd
  8660. # `,Á+$  MacPaint Document Format°dONLNd
  8661. =,*8‹(TH&MacPaint is a registered trademark of °dONLNd
  8662. c,‹8‰)≤C
  8663. °dONLNd
  8664. d,‰8)LARIS
  8665. °dONLNd
  8666. i,8A)
  8667.  Corporation. ◊4◊˘
  8668. (Ï64) of 4(Ï;)Things You Wanted to Know About _PackBitsˇ ◊#ˇ ˇˇˇˇ#◊†Ç 
  8669. /ZÅ#
  8670.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  8671. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  8672. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  8673. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  8674. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  8675.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  8676. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  8677. IR.°dONLNdz<çï(ßZ'Palette Manager Changes in System 6.0.2
  8678. °dONLNd(å<õr*Imaging°dONLNd0å8õ˛)¸M.IM.PaletteManagerChanges
  8679. °dONLNdKß<≥q(œZ Written by:°dONLNdWßÑ≥Œ)HGuillermo Ortiz°dONLNdgßæ≥˛(œ‹ October 1988°dONLNdtø<Àl(ÁZ>This Technical Note describes the changes and enhancements to °dONLNd≤ølÀ˛(Áäthe Palette Manager in System°dONLNd–À<◊Ê(ÛZ#Software 6.0.2 and future versions. X
  8680. °dONLNdÙ¸< ª*4Application Palette
  8681. °dONLNd<#ö*MApplications now have the ability to define a default palette for the system °dONLNdUö#˛(?∏to use when it needs°dONLNdj#</Û(KZ'to define the color environment (i.e., °dONLNdë#Û/˛)∑4when it creates a color window without an associated°dONLNdΔ/<;÷(WZ"palette or displays a dialog box).°dONLNdÈG<S2*6The application palette feature is especially cool in °dONLNdG2S˙)ˆ(cases where a color application uses old°dONLNdGG˙S˛)»-°dONLNdHS<_fi({ZYstyle dialogs and alerts because without an application palette, the system will use the °dONLNd°Sfi_˛({¸default°dONLNd©_<k˝(áZ)palette to define the color environment. °dONLNd“_˝k˛)¡5 Since the system uses the default palette, the color°dONLNdk<wì(ìZenvironment may °dONLNdkìwΩ)Wchange (°dONLNd kΩwœ)*will°dONLNd$kœw˛): change in 16-color mode) to cause some “cosmic” colors to°dONLNd_w<Ɉ(üZ'appear in the active window.  Defining °dONLNdÜwˆÉ˛)∫8a default application palette with two colors, black and°dONLNdøÉ<èΩ(´Zwhite, solves this problem.°dONLNd€õ<ßÔ*(If the system needs a palette to define °dONLNdõÔ߲)≥9a color environment, it looks in the resource fork of the°dONLNd=®<¥î(–Zapplication for the ,
  8682. Courier°dONLNdQßî≥⁄)X
  8683. 'pltt' ID °dONLNd[ß⁄≥¯)F= 0 °dONLNd_®¯¥˛)8resource and uses the palette which it contains.  If the°dONLNdò¥<¿`(‹Zsystem °dONLNdü¥`¿˛)$Ycannot find this resource in the application’s resource fork, it will use its own default°dONLNd˘¡<Õå(ÈZpalette (resource °dONLNd ¿åÃÓ)P'pltt' ID = 0 °dONLNd¡ÓÕQ)bin the System file) if °dONLNd0¡QÕ˛)c&present, or, if necessary, it will use°dONLNdWÕ<ŸÎ(ıZ'the Palette Manager’s built-in palette.°dONLNdÊ<Ú†*>Once an application has set its color environment (by calling °dONLNdΩ†ÒÊ(æ
  8684. _InitMenus°dONLNd«ÊÊÚÙ)F, °dONLNd…ÊÙÚ˛)or°dONLNdÃÚ<˛ó(Z
  8685. _InitPalettes°dONLNdŸÛóˇƒ)[
  8686.  in weird °dONLNd„Ûƒˇ˛)-Binstances when there are no menus) it can find the default palette°dONLNd&< o((Z by calling °dONLNd1ˇo >)3GetPalette ( WindowPtr (-1) )°dONLNdN> ´)œ or change the default °dONLNde´ ˛)mpalette by calling°dONLNdx <£(5Z/SetPalette ( WindowPtr (-1), newDefPltt, true )°dONLNdß
  8687. £÷(5¡.  Note °dONLNdØ
  8688. ÷˛)3that the°dONLNd∏<&ñ(BZinitialization of the °dONLNdŒñ&))ZPalette Manager with a call to °dONLNdÌ)%o)ì
  8689. _InitMenus°dONLNd˜o&·)F is contrary to the way °dONLNd·&˛)rInside°dONLNd&<2m(NZ    Macintosh°dONLNd&m2N)1-, Volume V, The Palette Manager documents it.
  8690. °dONLNdMJ<Yfi(uZOne Palette, Many Ports
  8691. °dONLNdef<rÑ* You can now °dONLNdqfÑr*)H associate one palette with many °dONLNdëe*qi)¶    CGrafPort°dONLNdöfirÜ)? and °dONLNdüeÜq∑)CWindow°dONLNd¶f∑r˛)1 records, thus°dONLNdµr<~¶(öZsimplifying the use of °dONLNdÃr¶~˛)jEa single palette with multiple ports and windows; System Software 6.0°dONLNd~<äè(¶ZKand earlier require copies of the palette to use it with different windows. ◊X◊
  8692. *F'Palette Manager Changes in System 6.0.2(Ï1) of 3ˇ°¿Ù%%DSIDICT:_cv
  8693. currentdict /bu known {bu}if
  8694. userdict /_cv known not{userdict /_cv 30 dict put}if
  8695. _cv begin
  8696. /bdf{bind def}bind def
  8697. currentscreen/cs exch def/ca exch def/cf exch def
  8698. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  8699. /ss{//cf //ca //cs setscreen}bdf
  8700. /stg{ss setgray}bdf
  8701. /strgb{ss setrgbcolor}bdf
  8702. /stcmyk{ss cvcmyk}bdf
  8703. /min1{dup 0 eq{pop 1}if}bdf
  8704. end
  8705. currentdict /bn known {bn}if
  8706. †øD◊#ˇ ˇˇˇˇ#◊ 
  8707. IR,Times
  8708. .+6-Macintosh Technical Notes /4/˘
  8709. °dONLNd)O*CAlthough this ability to associate one palette with multiple ports °dONLNdCO)⁄(Emand windows will allow the°dONLNd^*6P(R6
  8710. use of calls °dONLNdk*P6e)8like ,
  8711. Courier°dONLNdp)e5π) _PmForeColor°dONLNd|*π6“)T and °dONLNdÅ)“5&) _PmBackColor°dONLNdç*&6Q)T
  8712. , calling °dONLNdó)Q5¡)+_ActivatePalette°dONLNdß*¡6⁄)p with°dONLNd≠6B@(^6Ban off-screen port does nothing, and as a result, calling it with °dONLNdÔ6@B⁄(^^!an off-screen port will associate°dONLNdBNé(j6Qthe palette with the port but will not cause any change in the color environment.°dONLNdc[g*2One important implication of this feature is that °dONLNdïZf[)Ë
  8713. DisposeWindow°dONLNd¢[[gd)[ (°dONLNd§Zdfø)    
  8714. _DisposWindow°dONLNd±[øg⁄)[) will°dONLNd∏gs1(è6=not dispose of the associated palette automatically since it °dONLNdıg1s⁄(èO"may be allocated to other ports or°dONLNdsƒ(õ6Iwindows.  The only exception to this behavior is when an application has °dONLNdasƒ⁄(õ‚used°dONLNdfãz(®6_GetNewCWindow°dONLNdtÄzå)b" to create the window, there is a °dONLNdñã=)ô'pltt'°dONLNdúÄ=åæ)* resource with the same ID °dONLNd∑Äæå⁄)Åas the°dONLNdæçô‰(µ6+window, and the application has not called °dONLNdÈå‰ò1)à _GetPalette°dONLNdÙç1ôÅ)M for the window.
  8715. °dONLNd±¿w(‹6
  8716. Color Updates
  8717. °dONLNdÕŸ*1System version 6.0.2 also introduces a new call, °dONLNdDÃÿm(ı7 _NSetPalette°dONLNdPÕmŸ⁄)T, which complements°dONLNddŸÂe(6 _SetPalette°dONLNdo⁄eÊs)M.  °dONLNdrŸs«) _NSetPalette°dONLNd~⁄«Ê`)T has the same functionality as °dONLNdùŸ`Â≠)ô _SetPalette°dONLNd®⁄≠Ê⁄)M    , but the°dONLNd≤ÊÚP(6CUpdates°dONLNd∫ÁPÛˇ)8$ parameter has been modified from a °dONLNdfiÊˇÚ0)ØBoolean°dONLNdÂÁ0ÛM)1 to an °dONLNdÏÊMÚ~)Integer°dONLNdÛÁ~Ûµ)1  as follows:
  8718.     °dONLNdˇ
  8719. {(&6GPROCEDURE NSetPalette (dstWindow: WindowPtr; srcPalette: PaletteHandle;°dONLNdI    <†+$
  8720. nCUpdates: INTEGER);°dONLNd^Y(:6
  8721. INLINE $AA95;
  8722. °dONLNdl)5l* _NSetPalette°dONLNdx*l6o)T °dONLNdy*o6)$changes the palette associated with °dONLNdù)5Y)´    dstWindow°dONLNd¶*Y6j)? to °dONLNd™)j5∞)
  8723. srcPalette°dONLNd¥*∞6⁄)F
  8724. .  It also°dONLNdø6B`(^6@records whether the window wants to receive updates as a result °dONLNdˇ6`B⁄(^~of a change to its color°dONLNdCO¶(k6environment.  If you want °dONLNd2B¶NÂ)é    dstWindow°dONLNd;CÂOÎ)? °dONLNd<CÎO⁄),to be updated whenever its color environment°dONLNdiP\W(x6
  8725. changes, set °dONLNdvOW[ñ)?    nCUpdates°dONLNdPñ\ß)? to °dONLNdÉOß[˚) pmAllUpdates°dONLNdèP˚\)T.  If °dONLNdïP\⁄)'you are only interested in updates when°dONLNdΩ\hW(Ö6    dstWindow°dONLNdΔ]Wifi)? is the active window, set °dONLNd·\fih)á    nCUpdates°dONLNdÍ]i0)? to °dONLNdÓ\0h}) pmFgUpdates°dONLNd˘]}iã)M.  °dONLNd¸]ãi⁄)If you are only°dONLNd jv§(í6interested in updates when °dONLNd'i§u„)å    dstWindow°dONLNd0j„vÈ)? °dONLNd1jÈvã)is not the active window, set °dONLNdOiãu )¢    nCUpdates°dONLNdXj v⁄)? to°dONLNd\vÇe(ü6 pmBkUpdates°dONLNdgweÉi)M.
  8726.     °dONLNdièö∏(∂6 { NSetPalette Update Constants }°dONLNd䣯^*pmNoUpdates = °dONLNdô£ÑÆ¢)l$8000;°dONLNd†£®Ɖ)$ {no updates}°dONLNd≠≠∏^(‘6pmBkUpdates = °dONLNdº≠Ñ∏¢)l$A000;°dONLNd√≠®∏%)${background updates only}°dONLNd›∑¬^(fi6pmFgUpdates = °dONLNdÏ∑Ѭ¢)l$C000;°dONLNdÛ∑®¬%)${foreground updates only}°dONLNd
  8727. ¡Ãc(Ë6pmAllUpdates = °dONLNd¡Ñâ)l$E000;°dONLNd$¡®ÃÈ)$
  8728. {all updates}
  8729. °dONLNd2◊„e(6 _SetPalette°dONLNd=ÿe‰¯)M! retains its syntax and function:
  8730.     °dONLNd_˚v(6FPROCEDURE SetPalette (dstWindow: WindowPtr; srcPalette: PaletteHandle;°dONLNdß˙<õ+$
  8731. CUpdates: Boolean);°dONLNdªY(+6
  8732. INLINE $AA95;
  8733. °dONLNd…'7*Note:°dONLNdœ<'ò)$The trap words for °dONLNd‚ò&Ï)\ _NSetPalette°dONLNdÓÏ')T and °dONLNdÛ&P) _SetPalette°dONLNd˛P'S)M °dONLNdˇS'a)are°dONLNda'è)  identical.
  8734. °dONLNd?Ng(j6 CopyPalette
  8735.     °dONLNdZeI*=PROCEDURE CopyPalette (srcPalette, dstPalette: PaletteHandle;°dONLNdYd<o˙+$
  8736. &srcEntry,dstEntry,dstLength: INTEGER);°dONLNdÄnyY(ï6
  8737. INLINE $AAA1;
  8738. °dONLNdéÑêl* _CopyPalette°dONLNdöÖlë)T$ is a utility procedure that copies °dONLNdæÑêF)õ    dstLength°dONLNd«ÖFëI)? °dONLNd»ÖIë⁄)entries from the source palette°dONLNdËíû(∫61into the destination palette; the copy begins at °dONLNd    ëù8)ËsrcEntry°dONLNd    !í8ûU)8 and °dONLNd    &ëUùû)
  8739. dstEntry, °dONLNd    0íûû⁄)I
  8740. respectively. ◊4◊˘
  8741. (Ï62) of 3(ÏO'Palette Manager Changes in System 6.0.2ˇ8◊#ˇ ˇˇˇˇ#◊ 
  8742. IR,Times
  8743. .+Z-Developer Support Center(-Ê October 1988 /X/,
  8744. Courier
  8745. °dONLNd<)ê(FZ _CopyPalette°dONLNd ê*€)TJ will resize the destination palette when the number of entries after the °dONLNdV€*˛(F˘copy is°dONLNd^*<6Ø(RZgreater than the original.°dONLNdyB<Nê* _CopyPalette°dONLNdÖCêOƒ)T
  8746.  does not °dONLNdèCƒO⁄)4call °dONLNdîB⁄NJ)_ActivatePalette°dONLNd§CJO˛)p$, so the application is free to do a°dONLNd…O<[¡(wZKnumber of palette changes without causing a series of intermediate changes °dONLNdO¡[˛(wfl to the color°dONLNd!\<h(ÑZ)environment; the application should call °dONLNdJ[gt)»_ActivatePalette°dONLNdZ\th˛)p after completing all palette°dONLNdxh<tf(êZchanges.°dONLNdÅÅ<ç€*%If either of the palette handles are °dONLNd¶Ä€å)üNIL°dONLNd©Åç˜), °dONLNd´Ä˜åK) _CopyPalette°dONLNd∑ÅKçè)T does nothing. ◊X◊
  8747. (ÏZ'Palette Manager Changes in System 6.0.2(Ï3) of 3ˇÏ◊#ˇ ˇˇˇˇ#◊†Ç 
  8748. /ZÅ#
  8749.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  8750. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  8751. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  8752. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  8753. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  8754.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  8755. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  8756. IR.°dONLNdn<Å˙(õZPalette Manager Q&As
  8757. °dONLNdÄ<èr*Imaging°dONLNdÄ^è˛(´|M.IM.PaletteMgr.Q&As
  8758. °dONLNd2õ<ßt(√Z Revised by:°dONLNd>õÑߡ)HDeveloper Support Center°dONLNdWõæß˛(√‹ October 1992°dONLNddß<≥q(œZ Written by:°dONLNdpßÑ≥ˇ)HDeveloper Support Center°dONLNdâßæ≥˛(œ‹ October 1990°dONLNdñø<À⁄(ÁZThis Technical Note contains a °dONLNdµø⁄À˛)û9collection of Q&As relating to a specific topic—questions°dONLNdÔÀ<◊†(ÛZGyou’ve sent the Developer Support Center (DSC) along with answers from °dONLNd6À†◊˛(Ûæthe DSC engineers.°dONLNdI◊<„u(ˇZ
  8759. While DSC °dONLNdS◊u„˛)9Lengineers have checked the Q&A content for accuracy, the Q&A Technical Notes°dONLNd†„<Ôq( Z don’t have °dONLNd´„qÔ˛)5Qthe editing and organization of other Technical Notes. The Q&A function is to get°dONLNd˝Ô<˚Ÿ(Znew technical information and °dONLNdÔŸ˚˛)ù6updates to you quickly, saving the polish for when the°dONLNdR˚<(#Z,information migrates into reference manuals.°dONLNd<k*:Q&As are now included with Technical Notes to make access °dONLNdπk˛(;âto technical updates easier for°dONLNdŸ<+.(GZ/you. If you have comments or suggestions about °dONLNd.+˛)Ú*Q&A content or distribution, please let us°dONLNd3+<7\(SZknow °dONLNd8+\7˛) Iby sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical°dONLNdÇ7<Ci(_Z9questions about Q&A content to DEVSUPPORT for resolution.°dONLNdºO<[«*NNew Q&As and Q&As revised this month are marked with a bar in the side margin."n  ÜXÜ
  8760. °dONLNd Ä<èã*40Macintosh Palette Manager and offscreen graphics
  8761. °dONLNd<è<õb* Written:°dONLNdEèàõ¨)L7/22/91°dONLNdMõ<ßÅ(√ZLast reviewed:°dONLNd\õàß¶)L8/1/92°dONLNdc≥<øk(€Z8The Macintosh Palette Manager doesn’t work on offscreen °dONLNdõ≥kø˛(€âenvironments the way you’d°dONLNd∂ø<Àa(ÁZexpect. °dONLNdæøaÀ˛)%WUnlike color windows, SetPalette will not change the offscreen’s color table; rather it°dONLNdÀ<◊b(ÛZ:just allows you to use PMForeColor and PMBackColor to set °dONLNdPÀb◊˛(ÛÄ!the current drawing color in that°dONLNdr◊<„N(ˇZ:environment. To change the offscreen’s color table you’ll °dONLNd¨◊N„˛(ˇl&need to convert the palette to a color°dONLNd”„<Ôfl( ZZtable and then set the resulting color table to the off screen. Calling Palette2CTab will °dONLNd-„flÔ˛( ˝do the°dONLNd4Ô<˚ò(Zconverting for you.°dONLNdH<È*%To get around having to use palettes °dONLNdmÈ˛)≠:to define the current drawing color in the off screen, you°dONLNd®<Z(;Z8can always use Index2Color and then RGBForeColor to get °dONLNd‡Z˛(;x"the color to be set for drawing. A°dONLNd<+˘(GZ%remake of GiMeDaPalette code sample, °dONLNd(˘+˛)Ω6available on the latest Developer CD Series disc, does°dONLNd_+<7o(SZ@offscreen drawing in place of having to continually copy a PICT.
  8762. °dONLNd†O<^∫*'8RestoreDeviceClut and color flash when application quits
  8763. °dONLNdŸ^<jb* Written:°dONLNd‚^àj¨)L8/23/91°dONLNdÍj<vÅ(íZLast reviewed:°dONLNd˘jàv¶)L8/1/92°dONLNdÇ<é\(™ZWhen °dONLNdÇ\é˛) Umy application, which uses a color palette, quits, there is momentary but distracting°dONLNd[é<ög(∂Z<flash of weird colors in the Finder windows and the desktop °dONLNdóégö˛(∂Ötemporarily appears in a weird°dONLNd∂ö<¶(¬Z+color. Is there any way to get around this? ◊X◊
  8764. **Palette Manager Q&As(Ï1) of 3ˇ°¿Ù%%DSIDICT:_cv
  8765. currentdict /bu known {bu}if
  8766. userdict /_cv known not{userdict /_cv 30 dict put}if
  8767. _cv begin
  8768. /bdf{bind def}bind def
  8769. currentscreen/cs exch def/ca exch def/cf exch def
  8770. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  8771. /ss{//cf //ca //cs setscreen}bdf
  8772. /stg{ss setgray}bdf
  8773. /strgb{ss setrgbcolor}bdf
  8774. /stcmyk{ss cvcmyk}bdf
  8775. /min1{dup 0 eq{pop 1}if}bdf
  8776. end
  8777. currentdict /bn known {bn}if
  8778. †øä◊#ˇ ˇˇˇˇ#◊ 
  8779. IR,Times
  8780. .+6-Macintosh Technical Notes /4/˘
  8781. °dONLNd)**___°dONLNd5A2*:When you quit, RestoreDeviceClut is called to restore the °dONLNd>52A⁄(]P"color table and an update event is°dONLNdaAM¿(i6&called to redraw the screen. It’s the °dONLNdáA¿M⁄)®:delay between the change in the color table and the update°dONLNd¬MY“(u6Vevent that causes the flash of incorrect colors to be displayed. This, unfortunately, °dONLNdM“Y⁄(uis°dONLNdYeU(Å6 unavoidable.
  8782. °dONLNd(}å´*';Restoring Finder desktop colors after using Palette Manager
  8783. °dONLNddåò>* Written:°dONLNdmådòà)L8/28/91°dONLNduò§](¿6Last reviewed:°dONLNdÑòd§Ç)L8/1/92°dONLNdã∞ºæ(ÿ6XAfter using the Macintosh Palette Manager, how do I restore the Finder’s desktop colors?°dONLNd‰º»** ___°dONLNdË‘‡∂*UThe Finder desktop’s colors are restored automatically on quitting applications that °dONLNd=‘∂‡⁄(¸‘use the°dONLNdE‡Ï(66Palette Manager. Colors aren’t restored automatically °dONLNd{‡Ï⁄)˝'when switching from your application to°dONLNd£Ï¯(65another, but if that application needs a certain set °dONLNdÿϯ⁄)Ë-of colors and uses the Palette Manager to get°dONLNd¯â( 6Gthem, then it’ll have them the moment it comes to the front. If you’re °dONLNdM¯â⁄( ßconcerned about°dONLNd]4(,6=applications that don’t use the Palette Manager, you can use °dONLNdö4⁄(,RRestoreDeviceClut(gd:GDHandle),°dONLNd∫ç(86Qpassing the handle to the GDevice of the screen you want to reset, or nil if you °dONLNd ç⁄(8´want to reset all°dONLNd(∏(D6of your devices. Passing nil °dONLNd:∏(⁄)†4to RestoreDeviceClut is your best bet, as it is very°dONLNdo(4?(P6:straightforward, and resets all of your monitors. You may °dONLNd©(?4⁄(P]not wish to do this, however,°dONLNd«4@¥(\6Tbecause RestoreDeviceClut is only available on machines with 32-bit color QuickDraw.°dONLNdLXà*ITo reset a screen’s GDevice for machines without 32-bit color QuickDraw, °dONLNdeLàX⁄(t¶you will need to°dONLNdvXd](Ä6Gkeep track of the color table.When your application starts up, get the °dONLNdΩX]d⁄(Ä{GDevice’s color table and°dONLNd◊dp∂(å6#save it—you’ll need it later. This °dONLNd˙d∂p⁄)û6value can be found at (**(**GDHandle).gdPMap).pmTable,°dONLNd1p|°(ò6Lwhere gdPMap is a PixMapHandle, and pmTable is a CTabHandle which tells you °dONLNd}p°|⁄(òø the absolute°dONLNdä|àv(§6Kcolors for this image. These data structures are found in Inside Macintosh °dONLNd’|và⁄(§îVolume V, pages 52°dONLNdËàîB(∞6and 119.°dONLNdÒ†¨S*@Build your application’s “world” using the Palette Manager, and °dONLNd1†S¨⁄(»qavoid low-level methods of°dONLNdL¨∏§(‘6Hchanging colors. When your application is about to quit and you want to °dONLNd∏⁄(‘¬ restore the°dONLNd†∏ƒ<(‡6Aenvironment to its original state, get the color table you saved °dONLNd·∏<ƒ⁄(‡Z!in the beginning. Convert this to°dONLNdƒ–w(Ï6Ha palette using CTab2Palette. Then set your window to this palette with °dONLNdKƒw–⁄(ÏïSetPalette. This will°dONLNda–‹ (¯6#cause the environment to update to °dONLNdÑ– ‹⁄)≤8the original color table that you initially got from the°dONLNdΩ‹ËH(6    GDevice. °dONLNdΔ‹HË⁄)0WIf the application that is behind your application is Palette Manager friendly, then it°dONLNd    ËÙ`(6Bwill restore the environment to its palette. You may also want to °dONLNd    `Ë`Ù⁄(~do this procedure at the°dONLNd    yÙF(6:suspend event, as shown in the DTS sample MacApp program, °dONLNd    ≥ÙF⁄(dFracApp. One of the problems°dONLNd    – A((6    that you °dONLNd    ŸA ⁄))Pwon’t be able to solve this way involves multiple monitors. You won’t know which°dONLNd
  8784. * ≈(46%one to update. Only the monitor that °dONLNd
  8785. O ≈⁄)≠9has the window that you’ve called ActivatePalette on will°dONLNd
  8786. â$;(@6update.°dONLNd
  8787. ë0</*2If your application changes the color environment °dONLNd
  8788. √0/<⁄(XMwith the Palette Manager, then°dONLNd
  8789. ‚<HÄ(d6RestoreDeviceClut is °dONLNd
  8790. ˜<ÄH⁄)hEcalled automatically when your application quits. This means that you°dONLNd =HTI(p6
  8791. shouldn’t °dONLNd GHIT⁄)1Qhave to worry about restoring the palette if you don’t want to. There is a catch,°dONLNd ôT`f(|6<however (there always is). When you use the SADE version of °dONLNd ’Tf`⁄(|ÑMultiFinder (6.1b9), it°dONLNd Ì`l?(à6>prevents this from automatically happening. Other versions of °dONLNd +`?l⁄(à] MultiFinder don’t have this side°dONLNd Llx6(î6effect.
  8792. °dONLNd Têü¶*':SetPalette cUpdates, NSetPalette, and window update events
  8793. °dONLNd èü´>* Written:°dONLNd òüd´à)L9/26/91 ◊4◊˘
  8794. (Ï62) of 3(ÏõPalette Manager Q&Asˇ
  8795. ò◊#ˇ ˇˇˇˇ#◊ 
  8796. IR,Times
  8797. .+Z-Developer Support Center(-Ê October 1992 /X/
  8798. °dONLNd<)Å(EZLast reviewed:°dONLNdà)¶)L8/1/92°dONLNd5<Afi(]ZUWhen I pass false in the cUpdates parameter to SetPalette, I still get update events °dONLNdk5fiA˛(]¸to that°dONLNdsA<M6(iZ2window when I modify its palette. What’s going on?°dONLNd¶M<YN* ___°dONLNd™e<q£*KSetPalette’s cUpdates parameter controls whether color-table changes cause °dONLNdıe£q˛(ç¡that window to get°dONLNdq<}d(ôZ<update events only if that window is NOT frontmost. If that °dONLNdDqd}˛(ôÇwindow is frontmost, then any°dONLNdb}<âé(•ZKchanges to its palette causes it to get an update event regardless of what °dONLNd≠}éâ˛(•¨the cUpdates parameter°dONLNdƒâ<ïí(±Zis. When you call °dONLNd÷âíï˛)VJSetEntryColor and then ActivatePalette for your front-most window, it gets°dONLNd!ï<°fl(ΩZ!an update event because it’s the °dONLNdBïfl°˛)£5front-most window even though you passed false in the°dONLNdx°<≠˘(…Z&cUpdates parameter. Another important °dONLNdû°˘≠˛)Ω7point is that windows that don’t have palettes also get°dONLNd÷≠<πg(’Z>update events even when another window’s palette is activated.°dONLNd≈<—A*6Fortunately, system software version 6.0.2 introduced °dONLNdK≈A—˛(Ì_&the NSetPalette routine, which you can°dONLNdr—<›¥(˘ZLfind documented in the Macintosh Technical Note “Palette Manager Changes in °dONLNdæ—¥›˛(˘“System 6.0.2,”°dONLNdÕ›<ÈP(Zand °dONLNd—›PÈ˛)Ton page 20-20 in the revamped Palette Manager chapter of Inside Macintosh Volume VI.°dONLNd&È<ıì(ZMThis variation of SetPalette gives you a lot more flexibility in controlling °dONLNdsÈìı˛(±whether your window°dONLNdáı<Y(Z7gets an update event than SetPalette does. If you pass °dONLNdæıY˛(wpmAllUpdates in the nCUpdates°dONLNd‹<
  8799. k()Z@parameter, then that window gets an update event when either it °dONLNdk
  8800. ˛()âor another window’s palette is°dONLNd;
  8801. <^(5Z;activated. If you pass pmFgUpdates, then it gets an update °dONLNdv
  8802. ^˛(5|!event when a palette is activated°dONLNdò<%T(AZonly °dONLNdùT%˛)\if it’s the front-most window (in effect, it only gets an update event if its own palette is°dONLNd˙%<1’(MZTactivated). If you pass pmBkUpdates, then it gets an update event when a palette is °dONLNdN%’1˛(MÛ    activated°dONLNdX1<=ù(YZonly if it’s not the °dONLNdm1ù=˛)aEfront-most window (in effect, it only gets an update event if another°dONLNd≥=<Ií(eZwindow’s palette °dONLNdƒ=íI˛)VFis activated). If you pass pmNoUpdates, then that window never gets an°dONLNd I<U—(qZUupdate event from any window’s palette being activated, including that window itself. ◊X◊
  8803. (ÏZPalette Manager Q&As(Ï3) of 3ˇd◊#ˇ ˇˇˇˇ#◊†Ç 
  8804. /ZÅ
  8805.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  8806. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  8807. .R≈R…x(+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  8808. Ω({íDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  8809. 0Ûe(UÎ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  8810.     û?+&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  8811. ze(Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  8812. IR.°dONLNdz<ç[(ßZPicture Comments—The Real Deal
  8813. °dONLNdå<õr*Imaging°dONLNd'åvõ˛(∑îM.IM.PictComments
  8814. °dONLNd9ß<≥t(œZ Revised by:°dONLNdEßÑ≥ )H
  8815. Joseph Maurer°dONLNdSßæ≥˛(œ‹ October 1992°dONLNd`≥<øq(€Z Written by:°dONLNdl≥Ñø–)HGinger Jernigan°dONLNd|≥±ø˛(€œ
  8816. November 1986°dONLNdäÀ<◊‹(ÛZChanges since March 1988: °dONLNd§À‹◊>)†This Note (formerly °dONLNd∏À>◊Ú)b&titled “Optimizing for the LaserWriter°dONLNdfiÀÚ◊˛)¥—°dONLNdfl◊<„%(ˇZ-PicComments”) describes the picture comments °dONLNd ◊%„˛)È,defined and interpreted by the Apple printer°dONLNd9„<Ô( Zdrivers. Most °dONLNdG„Ô˛)CNof the picture comments are specific to PostScript, but we renamed the Note to°dONLNdñÔ<˚û(ZLemphasize that LaserWriter printers are not necessarily PostScript devices, °dONLNd‚Ôû˚˛(ºand that QuickDraw°dONLNdı˚<—(#ZLprinter drivers may implement their own picture comment handling. This Note °dONLNdA˚—˛(#Ôhas been°dONLNdJ< (/ZUcompletely rewritten and incorporates all additional insights gained during the last °dONLNdü ˛(/Ë
  8817. few years.°dONLNd™<`(;ZWe are °dONLNd±`˛)$Qalso much more determined now to discourage the use of obsolete and problem-laden°dONLNd<+(GZ-(although still supported) picture comments, °dONLNd0+˛)Ÿ,and we carefully point out known problems or°dONLNd]+<7ƒ(SZlimitations of each comment. bXb
  8818. °dONLNdz\<kè*4 Introduction
  8819. °dONLNdáx<ÑR*The ,
  8820. Courier°dONLNdãwRÉÉ)QDProcs°dONLNdíxÉÑ¿)1
  8821.  record (see °dONLNdüx¿Ñ)=Inside Macintosh°dONLNdØxÑ∑)R" Volume I, page 197) reflects the °dONLNd—x∑Ñ˛)•foundations of°dONLNd‡Ö<ëì(≠Zthe architecture of °dONLNdÙÖìëÁ)WQuickDraw. The °dONLNdÑÁê4)T commentProc°dONLNdÖ4ë˛)M+ field points to a procedure that processes°dONLNd:í<û^(∫Z;picture comments, as included in a picture by means of the °dONLNduë^ù§(∫|
  8822. PicComment°dONLNdí§û·)F  procedure (°dONLNdãí·û˛)=Inside°dONLNdíû<™m(ΔZ    Macintosh°dONLNdõûm™»)1 Volume I, page °dONLNd´û»™˛)[>189). This allows applications to include application-specific°dONLNdÍ™<∂"(“Z3additional information in the pictures they create.°dONLNd√<œR*The °dONLNd"¬RŒÉ)QDProcs°dONLNd)√ÉœG)1) record also is the key to understanding °dONLNdR√Gœ˛)ƒ#how Macintosh printer drivers work.°dONLNdv–<‹¬(¯ZWhen the application calls °dONLNd뜬€)Ü
  8823. PrOpenPage°dONLNdõ–‹o)F and draws into the °dONLNdØ–o‹˛)gprinting grafPort, the printer°dONLNdŒ›<ÈZ(Z9driver collects the drawing commands by hooking into the °dONLNd‹ZËã(xQDProcs°dONLNd›ãÈÿ)1 of the printing °dONLNd›ÿÈ˛)Mport. In°dONLNd(Í<ˆo(Z particular, °dONLNd4ÍoˆÎ)3if an application calls the °dONLNdPÈÎı1)|
  8824. PicComment°dONLNdZÍ1ˆ˛)F* procedure while drawing into the printing°dONLNdÖˆ<(Z_grafPort, the printer driver gets a chance to capture and process the information contained in °dONLNd‰ˆ˛(the°dONLNdË<X(+Zkind°dONLNdÏXo) and °dONLNdÒoµ)
  8825. dataHandle°dONLNd˚µÔ)F  parameters.°dONLNd<'Œ(CZDuring the development of the °dONLNd&Œ'˛)í@original LaserWriter driver, it became obvious that applications°dONLNdg'<3:(OZ7should be able to take advantage of certain PostScript °dONLNdû':3˛)˛)features that were not accessible through°dONLNd»3<?¬([Zstandard QuickDraw calls, °dONLNd‚3¬?˛)Ü@such as rotated text and graphics, dashed lines, fractional line°dONLNd#?<KÅ(gZCwidths, and smoothed polygons. Also, certain applications needed a °dONLNdf?ÅK˛(güway to transmit their own°dONLNdÄK<Wü(sZJnative PostScript instructions to the printer. Picture comments seemed to °dONLNd KüW˛(sΩbe the ideal vehicle°dONLNdflW<c—(Z!for providing these capabilities.°dONLNd    o<{b*?Unfortunately, there are conflicts with the device-independent °dONLNd    @ob{˛(óÄ nature of the Macintosh Printing°dONLNd    a{<á‰(£Z$Manager architecture. In this Note, °dONLNd    Ö{‰á˛)®8we still want to document picture comments as completely°dONLNd    æá<ì∂(ØZand correctly as possible; °dONLNd    Ÿá∂ì˛)zDand we want to tell you how to use the best of their features, while°dONLNd
  8826. ì<üu(ªZBmaintaining the important goal of device-independent printing and °dONLNd
  8827. `ìuü˛(ªìall- purpose PICTs. (This is°dONLNd
  8828. }ü<´fi(«Z#why it has such a painful history!) ◊X◊
  8829. *%Picture Comments—The Real Deal(Ïˇ1) of 25ˇ°¿Ù%%DSIDICT:_cv
  8830. currentdict /bu known {bu}if
  8831. userdict /_cv known not{userdict /_cv 30 dict put}if
  8832. _cv begin
  8833. /bdf{bind def}bind def
  8834. currentscreen/cs exch def/ca exch def/cf exch def
  8835. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  8836. /ss{//cf //ca //cs setscreen}bdf
  8837. /stg{ss setgray}bdf
  8838. /strgb{ss setrgbcolor}bdf
  8839. /stcmyk{ss cvcmyk}bdf
  8840. /min1{dup 0 eq{pop 1}if}bdf
  8841. end
  8842. currentdict /bn known {bn}if
  8843. †ø&◊#ˇ ˇˇˇˇ#◊ 
  8844. IR,Times
  8845. .+6-Macintosh Technical Notes /4/˘
  8846. °dONLNd)5Î*$*First, we give an overview of the picture °dONLNd*)Î5⁄)”,comments as currently implemented by Apple’s°dONLNdW5Az(]6printer drivers. This °dONLNdm5zA⁄)bFleads us immediately to the problem section “Cohabitation of QuickDraw°dONLNd¥AM˛(i6.and PostScript,” which also shows how to keep °dONLNd‚A˛M⁄)Ê,the QuickDraw and PostScript graphics states°dONLNdMYÃ(u6Zsynchronized during printing. Finally, we discuss all the picture comments by subject, in °dONLNdiMÃY⁄(uÍthe°dONLNdmYeú(Å6order suggested by Table 1.
  8847. °dONLNdâ}å›*'Picture Comments Repertoire
  8848. °dONLNd•ò§ë*LThe following picture comments are recognized by all PostScript LaserWriter °dONLNdÒòë§⁄(¿Ødrivers version°dONLNd§∞W(Ã63.1 and later.°dONLNdºi»à+Q0Table 1  PostScript LaserWriter Picture Comments°dONLNdE‘ø‡‹+VData °dONLNdN‡.ÏJ(LType°dONLNdS‡çÏ©)_Kind°dONLNdX‡¿Ïÿ)3Size°dONLNd]‡ÙÏ
  8849. )4Data°dONLNdb‡AÏÇ)M Description
  8850.     °dONLNdo¯.V(L    TextBegin°dONLNdy¯çú)_150°dONLNd}¯“◊)E6°dONLNd¯.)0
  8851. TTxtPicRec°dONLNdä¯Aã)?Begin text function°dONLNdü.
  8852. M()LTextEnd°dONLNdßç
  8853. ú)_151°dONLNd´“
  8854. ◊)E0°dONLNd≠
  8855. )0NIL°dONLNd±A
  8856. Ç)?End text function°dONLNdƒ .](3L StringBegin°dONLNd– çú)_152°dONLNd‘ “◊)E0°dONLNd÷ )0NIL°dONLNd⁄ A¢)?Begin string delimitation°dONLNdı.!T(=L    StringEnd°dONLNdˇç!ú)_153°dONLNd“!◊)E0°dONLNd!)0NIL°dONLNd    A!ô)?End string delimitation°dONLNd! .+X(GL
  8857. TextCenter°dONLNd, ç+ú)_154°dONLNd0 “+◊)E8°dONLNd2 +-)0
  8858. TTxtCenter°dONLNd= A+¶)?Offset to center of rotation°dONLNd[4.?e([L
  8859. LineLayoutOff°dONLNdi4ç?ú)_155°dONLNdm4“?◊)E0°dONLNdo4?)0NIL°dONLNds4A?∏)? Turn LaserWriter line layout off°dONLNdï>.Id(eL LineLayoutOn°dONLNd¢>çIú)_156°dONLNd¶>“I◊)E0°dONLNd®>I)0NIL°dONLNd¨>AI∑)?Turn LaserWriter line layout on°dONLNdÃHS(o6#°dONLNdŒH.Sq)ClientLineLayout°dONLNdflHçSú)_157°dONLNd„H–S⁄)C16°dONLNdÊHS))2    TClientLL°dONLNdHAS®)?Customize line layout error°dONLNdRA]n*
  8860. distribution°dONLNd \.gW(ÉL    PolyBegin°dONLNd*\çgú)_160°dONLNd.\“g◊)E0°dONLNd0\g)0NIL°dONLNd4\Agò)?Begin special polygon°dONLNdKf.qN(çLPolyEnd°dONLNdSfçqú)_161°dONLNdWf“q◊)E0°dONLNdYfq)0NIL°dONLNd]fAqè)?End special polygon°dONLNdrp.{Y(óL
  8861. PolyIgnore°dONLNd}pç{ú)_163°dONLNdÅp“{◊)E0°dONLNdÉp{)0NIL°dONLNdápA{∂)?Ignore following polygon data°dONLNd¶z.Ö^(°L
  8862. PolySmooth°dONLNd±zçÖú)_164°dONLNdµz“Ö◊)E1°dONLNd∑zÖ&)0PolyVerb°dONLNd¿zAÖÜ)?Close, Fill, Frame°dONLNd‘Ñ.èV(´L    PolyClose°dONLNdfiÑçèú)_165°dONLNd‚Ñ“è◊)E0°dONLNd‰Ñè)0NIL°dONLNdËÑAèà)?Close the polygon°dONLNd˚ò.£Z(øL
  8863. DashedLine°dONLNdòç£ú)_180°dONLNd
  8864. ò”£÷)F-°dONLNd ò£3)/ TDashedLine°dONLNdòA£∂)?Draw following lines as dashed°dONLNd8¢.≠[(…L
  8865. DashedStop°dONLNdC¢ç≠ú)_181°dONLNdG¢“≠◊)E0°dONLNdI¢≠)0NIL°dONLNdM¢A≠)?End dashed lines°dONLNd_¨.∑b(”L SetLineWidth°dONLNdl¨ç∑ú)_182°dONLNdp¨“∑◊)E4°dONLNdr¨∑)0Point°dONLNdx¨A∑†)?Set fractional line widths°dONLNdî¿.Ào(ÁLPostScriptBegin °dONLNd•¿çÀú)_190°dONLNd©¿“À◊)E0°dONLNd´¿À)0NIL°dONLNdØ¿AÀ≠)?Set driver state to PostScript°dONLNdœ .’f(ÒLPostScriptEnd °dONLNdfi ç’ú)_191°dONLNd‚ “’Ÿ)E0 °dONLNd ’)0NIL°dONLNdÈ A’ù)?Restore QuickDraw state°dONLNd‘.flp(˚LPostScriptHandle°dONLNd‘çflú)_192°dONLNd‘”fl÷)F-°dONLNd‘fl)/PSData °dONLNd!‘Aflü)?PostScript data in handle°dONLNd;fiÈ(6†°dONLNd=fi.Èe)PostScriptFile°dONLNdLfiçÈú)_193°dONLNdPfi”È÷)F-°dONLNdRfiÈ&)/FileName°dONLNd[fiAÈõ)?FileName in data handle°dONLNdsËÛ(6†°dONLNduË.Ûn)TextIsPostScript°dONLNdÜËçÛú)_194°dONLNdäË“Û◊)E0°dONLNdåËÛ)0NIL°dONLNdêËAÛ )?$QuickDraw text is sent as PostScript°dONLNdµÚ˝(6†°dONLNd∑Ú.˝Z)
  8866. ResourcePS°dONLNd¬Úç˝ú)_195°dONLNdΔÚ“˝◊)E8°dONLNd»Ú˝9)0
  8867. Type/ID/Index°dONLNd÷ÚA˝∫)?"PostScript data in a resource file°dONLNd˙¸.l(#L
  8868. PSBeginNoSave°dONLNd¸çú)_196°dONLNd ¸“◊)E0°dONLNd¸)0NIL°dONLNd¸A≠)?Set driver state to PostScript°dONLNd1(-6#°dONLNd3.a) SetGrayLevel°dONLNd@çú)_197°dONLNdD“◊)E4°dONLNdF)0Fixed°dONLNdLAÑ)?Call PostScript’s ,
  8869. Courier°dONLNd^Ñß)Csetgray°dONLNdeß…)#     operator°dONLNdp.%^(AL RotateBegin°dONLNd|ç%ú)_200°dONLNdÄ“%◊)E4°dONLNdÇ%))0    TRotation°dONLNdåA%Ü)?Begin rotated port°dONLNd†$./U(KL    RotateEnd°dONLNd™$ç/ú)_201°dONLNdÆ$“/◊)E0°dONLNd∞$/)0NIL°dONLNd¥$A/p)? End rotation°dONLNd¬..9`(UL RotateCenter°dONLNdœ.ç9ú)_202°dONLNd”.“9◊)E8°dONLNd’.9)0Center°dONLNd‹.A9¶)?Offset to center of rotation°dONLNd˘BM(i6#°dONLNd˚B.Mf)
  8870. FormsPrinting°dONLNd    BçMú)_210°dONLNd
  8871. B“M◊)E0°dONLNdBM)0NIL°dONLNdBAM“)?(Don’t clear print buffer after each page°dONLNd<LW(s6#°dONLNd>L.Wt)EndFormsPrinting°dONLNdOLçWú)_211°dONLNdSL“W◊)E0°dONLNdULW)0NIL°dONLNdYLAWŒ)?$End forms printing after PrClosePage
  8872. °dONLNd~Vb¸(~6&______________________________________°dONLNd•bn* †
  8873. °dONLNdßb*n¢)These comments are obsolete.
  8874. °dONLNdƒnz(ñ6#
  8875. °dONLNdΔn*zΔ)#These comments are not recommended.
  8876. °dONLNdÍíû~(∫6LMost of the comments in Table 1 were designed specifically for the original °dONLNd    6í~û⁄(∫úLaserWriter driver.°dONLNd    Jû™n(Δ6In fact, the term °dONLNd    \ûn™¶)V LaserWriter°dONLNd    gû¶™î)81 has been (and often still is) used in the sense °dONLNd    òûî™⁄)Óof “PostScript ◊4◊˘
  8877. (Ï62) of 25(ÏjPicture Comments—The Real Dealˇ∏◊#ˇ ˇˇˇˇ#◊ 
  8878. IR,Times
  8879. .+Z-Developer Support Center(-Ê October 1992 /X/
  8880. °dONLNd<)J(EZ4printer,” and the LaserWriter driver is known to be °dONLNd4J)˛(Eh#basically a QuickDraw-to-PostScript°dONLNdX)<5|(QZ<translator. Meanwhile, however, QuickDraw-based LaserWriter °dONLNdî)|5˛(Qömodels came out, so we°dONLNd´5<A≤(]Zshould start being more °dONLNd√5≤A˛)vBcareful in our terminology. This is why we insist on talking about°dONLNdA<M◊(iZWPostScript drivers or PostScript printers when a picture comme